This commit is contained in:
Pablu23
2024-05-21 15:17:29 +02:00
parent 20ad56b155
commit c1fa18fead
7 changed files with 300 additions and 160 deletions

View File

@@ -8,9 +8,10 @@ type Chapter struct {
Number string Number string
TimeStampUnix int64 TimeStampUnix int64
MangaId int MangaId int
UserId int
} }
func NewChapter(id int, mangaId int, url string, name string, number string, timeStampUnix int64) Chapter { func NewChapter(id int, mangaId int, userId int, url string, name string, number string, timeStampUnix int64) Chapter {
return Chapter{ return Chapter{
ChapterId: id, ChapterId: id,
Url: url, Url: url,
@@ -18,5 +19,6 @@ func NewChapter(id int, mangaId int, url string, name string, number string, tim
Number: number, Number: number,
TimeStampUnix: timeStampUnix, TimeStampUnix: timeStampUnix,
MangaId: mangaId, MangaId: mangaId,
UserId: userId,
} }
} }

View File

@@ -3,7 +3,6 @@ package database
type MangaDefinition struct { type MangaDefinition struct {
Id int `gorm:"primary_key;AUTO_INCREMENT"` Id int `gorm:"primary_key;AUTO_INCREMENT"`
Title string Title string
TimeStampUnix int64
Thumbnail []byte Thumbnail []byte
LastChapterNum string LastChapterNum string
// Chapters []Chapter // Chapters []Chapter
@@ -13,21 +12,31 @@ type MangaDefinition struct {
type Manga struct { type Manga struct {
Id int `gorm:"primary_key;AUTO_INCREMENT"` Id int `gorm:"primary_key;AUTO_INCREMENT"`
MangaDefinitionId int MangaDefinitionId int
Definition MangaDefinition `gorm:"foreignKey:MangaDefinitionId"` Definition MangaDefinition `gorm:"foreignKey:MangaDefinitionId"`
UserId int UserId int
User User
TimeStampUnix int64 TimeStampUnix int64
Chapters []Chapter `gorm:"foreignKey:MangaId"` Chapters []Chapter `gorm:"foreignKey:MangaId"`
} }
func NewMangaDefinition(id int, title string, timeStampUnix int64) MangaDefinition { func NewMangaDefinition(id int, title string) MangaDefinition {
return MangaDefinition{ return MangaDefinition{
Id: id, Id: id,
Title: title, Title: title,
TimeStampUnix: timeStampUnix,
LastChapterNum: "", LastChapterNum: "",
} }
} }
func NewManga(def MangaDefinition, user User, timeStampUnix int64) Manga {
return Manga{
MangaDefinitionId: def.Id,
Definition: def,
UserId: user.Id,
User: user,
TimeStampUnix: timeStampUnix,
}
}
// GetLatestChapter TODO: Cache this somehow // GetLatestChapter TODO: Cache this somehow
func (m *Manga) GetLatestChapter() (*Chapter, bool) { func (m *Manga) GetLatestChapter() (*Chapter, bool) {
// highest := int64(0) // highest := int64(0)

View File

@@ -6,7 +6,6 @@ type User struct {
LoginName string LoginName string
PwdHash []byte PwdHash []byte
Salt []byte Salt []byte
Mangas []Manga `gorm:"foreignKey:UserId"`
} }
// type UserManga struct { // type UserManga struct {

View File

@@ -5,40 +5,112 @@ import (
_ "embed" _ "embed"
"errors" "errors"
"fmt" "fmt"
"github.com/pablu23/mangaGetter/internal/database"
"github.com/pablu23/mangaGetter/internal/view"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"gorm.io/gorm"
"html/template" "html/template"
"net/http" "net/http"
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"github.com/pablu23/mangaGetter/internal/database"
"github.com/pablu23/mangaGetter/internal/view"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"gorm.io/gorm"
) )
func (s *Server) getSessionFromCookie(w http.ResponseWriter, r *http.Request) (*UserSession, error) {
cookie, err := r.Cookie("session")
if err != nil {
switch {
case errors.Is(err, http.ErrNoCookie):
// http.Error(w, "cookie not found", http.StatusBadRequest)
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
default:
fmt.Println(err)
http.Error(w, "server error", http.StatusInternalServerError)
}
}
session, ok := s.Sessions[cookie.Value]
if !ok {
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
return nil, errors.New("Unknown Session")
}
return session, err
}
func (s *Server) HandleRegister(w http.ResponseWriter, r *http.Request) {
s.Mutex.Lock()
defer s.Mutex.Unlock()
admin := database.User{
Id: 1,
DisplayName: "admin",
LoginName: "admin",
}
s.DbMgr.Db.Create(&admin)
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
}
func (s *Server) HandleLogin(w http.ResponseWriter, r *http.Request) {
s.Mutex.Lock()
defer s.Mutex.Unlock()
// Login
s.Sessions["abcd"] = &UserSession{
User: database.User{
Id: 1,
DisplayName: "admin",
LoginName: "admin",
},
}
cookie := http.Cookie{
Name: "session",
Value: "abcd",
Path: "/",
MaxAge: 3600,
Secure: true,
HttpOnly: false,
SameSite: http.SameSiteLaxMode,
}
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
title := r.PathValue("title") title := r.PathValue("title")
chapter := r.PathValue("chapter") chapter := r.PathValue("chapter")
url := fmt.Sprintf("/title/%s/%s", title, chapter) url := fmt.Sprintf("/title/%s/%s", title, chapter)
s.CurrSubUrl = url session, err := s.getSessionFromCookie(w, r)
s.PrevSubUrl = "" if err != nil {
s.NextSubUrl = "" return
s.LoadCurr() }
go s.LoadNext() session.CurrSubUrl = url
go s.LoadPrev() session.PrevSubUrl = ""
session.NextSubUrl = ""
s.LoadCurr(session)
go s.LoadNext(session)
go s.LoadPrev(session)
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
} }
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) { func (s *Server) HandleMenu(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Menu)) tmpl := template.Must(view.GetViewTemplate(view.Menu))
session, err := s.getSessionFromCookie(w, r)
if err != nil {
return
}
var all []*database.Manga var all []*database.Manga
_ = s.DbMgr.Db.Preload("Chapters").Where("user_id = ?", 1).Find(&all) _ = s.DbMgr.Db.Preload("Chapters").Where("user_id = ?", session.User.Id).Find(&all)
l := len(all) l := len(all)
mangaViewModels := make([]view.MangaViewModel, l) mangaViewModels := make([]view.MangaViewModel, l)
counter := 0 counter := 0
@@ -148,7 +220,7 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
Mangas: mangaViewModels, Mangas: mangaViewModels,
} }
err := tmpl.Execute(w, menuViewModel) err = tmpl.Execute(w, menuViewModel)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
@@ -177,63 +249,77 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) {
func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
// session, err := s.getSessionFromCookie(w, r)
// if err != nil {
// return
// }
go func() { go func() {
s.Mutex.Lock() // session.Mutex.Lock()
if s.PrevViewModel != nil { // if session.PrevViewModel != nil {
for _, img := range s.PrevViewModel.Images { // for _, img := range session.PrevViewModel.Images {
delete(s.ImageBuffers, img.Path) // delete(s.ImageBuffers, img.Path)
} // }
} // }
if s.CurrViewModel != nil { // if session.CurrViewModel != nil {
//
for _, img := range s.CurrViewModel.Images { // for _, img := range session.CurrViewModel.Images {
delete(s.ImageBuffers, img.Path) // delete(s.ImageBuffers, img.Path)
} // }
} // }
if s.NextViewModel != nil { // if session.NextViewModel != nil {
//
for _, img := range s.NextViewModel.Images { // for _, img := range session.NextViewModel.Images {
delete(s.ImageBuffers, img.Path) // delete(s.ImageBuffers, img.Path)
} // }
} // }
s.Mutex.Unlock() // session.Mutex.Unlock()
fmt.Println("Cleaned last Manga") fmt.Println("Cleaned last Manga")
}() }()
} }
func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) { func (s *Server) HandleCurrent(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Viewer)) tmpl := template.Must(view.GetViewTemplate(view.Viewer))
mangaId, chapterId, err := s.Provider.GetTitleIdAndChapterId(s.CurrSubUrl) session, err := s.getSessionFromCookie(w, r)
if err != nil {
return
}
mangaId, chapterId, err := s.Provider.GetTitleIdAndChapterId(session.CurrSubUrl)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
title, chapterName, err := s.Provider.GetTitleAndChapter(s.CurrSubUrl) title, chapterName, err := s.Provider.GetTitleAndChapter(session.CurrSubUrl)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
var manga database.MangaDefinition var mangaDef database.MangaDefinition
result := s.DbMgr.Db.First(&manga, mangaId) result := s.DbMgr.Db.First(&mangaDef, mangaId)
if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) { if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
manga = database.NewMangaDefinition(mangaId, title, time.Now().Unix()) mangaDef = database.NewMangaDefinition(mangaId, title)
} else { }
manga.TimeStampUnix = time.Now().Unix()
var manga database.Manga
result = s.DbMgr.Db.Where("user_id = ?", session.User.Id).First(&manga, "manga_definition_id = ?", mangaId)
if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
manga = database.NewManga(mangaDef, session.User, time.Now().Unix())
} }
var chapter database.Chapter var chapter database.Chapter
result = s.DbMgr.Db.First(&chapter, chapterId) result = s.DbMgr.Db.Where("user_id = ?", session.User.Id).First(&chapter, "chapter_id = ?", chapterId)
if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) { if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
chapterNumberStr := strings.Replace(chapterName, "ch_", "", 1) chapterNumberStr := strings.Replace(chapterName, "ch_", "", 1)
chapter = database.NewChapter(chapterId, mangaId, s.CurrSubUrl, chapterName, chapterNumberStr, time.Now().Unix()) chapter = database.NewChapter(chapterId, mangaId, session.User.Id, session.CurrSubUrl, chapterName, chapterNumberStr, time.Now().Unix())
} else { } else {
chapter.TimeStampUnix = time.Now().Unix() chapter.TimeStampUnix = time.Now().Unix()
} }
s.DbMgr.Db.Save(&mangaDef)
s.DbMgr.Db.Save(&manga) s.DbMgr.Db.Save(&manga)
s.DbMgr.Db.Save(&chapter) s.DbMgr.Db.Save(&chapter)
err = tmpl.Execute(w, s.CurrViewModel) err = tmpl.Execute(w, session.CurrViewModel)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
@@ -241,8 +327,8 @@ func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) {
func (s *Server) HandleImage(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleImage(w http.ResponseWriter, r *http.Request) {
u := r.PathValue("url") u := r.PathValue("url")
s.Mutex.Lock() s.Mutex.RLock()
defer s.Mutex.Unlock() defer s.Mutex.RUnlock()
buf := s.ImageBuffers[u] buf := s.ImageBuffers[u]
if buf == nil { if buf == nil {
fmt.Printf("url: %s is nil\n", u) fmt.Printf("url: %s is nil\n", u)
@@ -271,7 +357,12 @@ func (s *Server) HandleFavicon(w http.ResponseWriter, _ *http.Request) {
func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Next") fmt.Println("Received Next")
if s.PrevViewModel != nil { session, err := s.getSessionFromCookie(w, r)
if err != nil {
return
}
if session.PrevViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) { go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock() s.Mutex.Lock()
for _, img := range viewModel.Images { for _, img := range viewModel.Images {
@@ -279,26 +370,31 @@ func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) {
} }
s.Mutex.Unlock() s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last") fmt.Println("Cleaned out of scope Last")
}(*s.PrevViewModel, s) }(*session.PrevViewModel, s)
} }
if s.NextViewModel == nil || s.NextSubUrl == "" { if session.NextViewModel == nil || session.NextSubUrl == "" {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return return
} }
s.PrevViewModel = s.CurrViewModel session.PrevViewModel = session.CurrViewModel
s.CurrViewModel = s.NextViewModel session.CurrViewModel = session.NextViewModel
s.PrevSubUrl = s.CurrSubUrl session.PrevSubUrl = session.CurrSubUrl
s.CurrSubUrl = s.NextSubUrl session.CurrSubUrl = session.NextSubUrl
go s.LoadNext() go s.LoadNext(session)
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
} }
func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) { func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Prev") fmt.Println("Received Prev")
if s.NextViewModel != nil {
session, err := s.getSessionFromCookie(w, r)
if err != nil {
return
}
if session.NextViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) { go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock() s.Mutex.Lock()
for _, img := range viewModel.Images { for _, img := range viewModel.Images {
@@ -306,20 +402,20 @@ func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
} }
s.Mutex.Unlock() s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last") fmt.Println("Cleaned out of scope Last")
}(*s.NextViewModel, s) }(*session.NextViewModel, s)
} }
if s.PrevViewModel == nil || s.PrevSubUrl == "" { if session.PrevViewModel == nil || session.PrevSubUrl == "" {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return return
} }
s.NextViewModel = s.CurrViewModel session.NextViewModel = session.CurrViewModel
s.CurrViewModel = s.PrevViewModel session.CurrViewModel = session.PrevViewModel
s.NextSubUrl = s.CurrSubUrl session.NextSubUrl = session.CurrSubUrl
s.CurrSubUrl = s.PrevSubUrl session.CurrSubUrl = session.PrevSubUrl
go s.LoadPrev() go s.LoadPrev(session)
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
} }
@@ -363,13 +459,17 @@ func (s *Server) HandleNewQuery(w http.ResponseWriter, r *http.Request) {
url := fmt.Sprintf("/title/%s", sub) url := fmt.Sprintf("/title/%s", sub)
s.CurrSubUrl = url session, err := s.getSessionFromCookie(w, r)
s.PrevSubUrl = "" if err != nil {
s.NextSubUrl = "" return
s.LoadCurr() }
session.CurrSubUrl = url
session.PrevSubUrl = ""
session.NextSubUrl = ""
s.LoadCurr(session)
go s.LoadNext() go s.LoadNext(session)
go s.LoadPrev() go s.LoadPrev(session)
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
} }

View File

@@ -4,50 +4,57 @@ import (
"bytes" "bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"github.com/pablu23/mangaGetter/internal/database"
"github.com/pablu23/mangaGetter/internal/provider"
"github.com/pablu23/mangaGetter/internal/view"
"io" "io"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
"github.com/pablu23/mangaGetter/internal/database"
"github.com/pablu23/mangaGetter/internal/provider"
"github.com/pablu23/mangaGetter/internal/view"
) )
type Server struct { type Server struct {
ImageBuffers map[string][]byte
Provider provider.Provider
DbMgr *database.Manager
Mutex *sync.RWMutex
Sessions map[string]*UserSession
}
type UserSession struct {
User database.User
// Mutex *sync.Mutex
PrevSubUrl string
CurrSubUrl string
NextSubUrl string
PrevViewModel *view.ImageViewModel PrevViewModel *view.ImageViewModel
CurrViewModel *view.ImageViewModel CurrViewModel *view.ImageViewModel
NextViewModel *view.ImageViewModel NextViewModel *view.ImageViewModel
ImageBuffers map[string][]byte
Mutex *sync.Mutex
NextSubUrl string
CurrSubUrl string
PrevSubUrl string
Provider provider.Provider
IsFirst bool
IsLast bool
DbMgr *database.Manager
} }
func New(provider provider.Provider, db *database.Manager) *Server { func New(provider provider.Provider, db *database.Manager) *Server {
s := Server{ s := Server{
ImageBuffers: make(map[string][]byte), ImageBuffers: make(map[string][]byte),
Sessions: make(map[string]*UserSession),
Provider: provider, Provider: provider,
DbMgr: db, DbMgr: db,
Mutex: &sync.Mutex{}, Mutex: &sync.RWMutex{},
} }
return &s return &s
} }
func (s *Server) Start(port int) error { func (s *Server) Start(port int) error {
http.HandleFunc("/register", s.HandleRegister)
http.HandleFunc("/login", s.HandleLogin)
http.HandleFunc("/", s.HandleMenu) http.HandleFunc("/", s.HandleMenu)
http.HandleFunc("/new/", s.HandleNewQuery) http.HandleFunc("/new/", s.HandleNewQuery)
http.HandleFunc("/new/title/{title}/{chapter}", s.HandleNew) http.HandleFunc("/new/title/{title}/{chapter}", s.HandleNew)
@@ -62,74 +69,66 @@ func (s *Server) Start(port int) error {
http.HandleFunc("GET /setting/set/{setting}/{value}", s.HandleSettingSet) http.HandleFunc("GET /setting/set/{setting}/{value}", s.HandleSettingSet)
// Update Latest Chapters every 5 Minutes // Update Latest Chapters every 5 Minutes
go func(s *Server) { // go func(s *Server) {
time.AfterFunc(time.Second*10, func() { // time.AfterFunc(time.Second*10, func() {
var all []*database.Manga // var all []*database.Manga
s.DbMgr.Db.Find(&all) // s.DbMgr.Db.Find(&all)
for _, m := range all { // for _, m := range all {
err, updated := s.UpdateLatestAvailableChapter(m) // err, updated := s.UpdateLatestAvailableChapter(m)
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
if updated { // if updated {
s.DbMgr.Db.Save(m) // s.DbMgr.Db.Save(m)
} // }
} // }
}) // })
//
for { // for {
select { // select {
case <-time.After(time.Minute * 5): // case <-time.After(time.Minute * 5):
var all []*database.Manga // var all []*database.Manga
s.DbMgr.Db.Find(&all) // s.DbMgr.Db.Find(&all)
for _, m := range all { // for _, m := range all {
err, updated := s.UpdateLatestAvailableChapter(m) // err, updated := s.UpdateLatestAvailableChapter(m)
if err != nil { // if err != nil {
fmt.Println(err) // fmt.Println(err)
} // }
if updated { // if updated {
s.DbMgr.Db.Save(m) // s.DbMgr.Db.Save(m)
} // }
} // }
} // }
} // }
}(s) // }(s)
//
fmt.Println("Server starting...") fmt.Println("Server starting...")
err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil) err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
return err return err
} }
func (s *Server) LoadNext() { func (s *Server) LoadNext(session *UserSession) {
c, err := s.Provider.GetHtml(s.CurrSubUrl) next, err := s.Provider.GetHtml(session.CurrSubUrl)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.NextSubUrl = "" session.NextSubUrl = ""
s.NextViewModel = nil session.NextViewModel = nil
return
}
next, err := s.Provider.GetNext(c)
if err != nil {
fmt.Println(err)
s.NextSubUrl = ""
s.NextViewModel = nil
return return
} }
html, err := s.Provider.GetHtml(next) html, err := s.Provider.GetHtml(next)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.NextSubUrl = "" session.NextSubUrl = ""
s.NextViewModel = nil session.NextViewModel = nil
return return
} }
imagesNext, err := s.AppendImagesToBuf(html) imagesNext, err := s.AppendImagesToBuf(html)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.NextSubUrl = "" session.NextSubUrl = ""
s.NextViewModel = nil session.NextViewModel = nil
return return
} }
@@ -141,39 +140,39 @@ func (s *Server) LoadNext() {
full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1) full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1)
s.NextViewModel = &view.ImageViewModel{Images: imagesNext, Title: full} session.NextViewModel = &view.ImageViewModel{Images: imagesNext, Title: full}
s.NextSubUrl = next session.NextSubUrl = next
fmt.Println("Loaded next") fmt.Println("Loaded next")
} }
func (s *Server) LoadPrev() { func (s *Server) LoadPrev(session *UserSession) {
c, err := s.Provider.GetHtml(s.CurrSubUrl) c, err := s.Provider.GetHtml(session.CurrSubUrl)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.PrevSubUrl = "" session.PrevSubUrl = ""
s.PrevViewModel = nil session.PrevViewModel = nil
return return
} }
prev, err := s.Provider.GetPrev(c) prev, err := s.Provider.GetPrev(c)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.PrevSubUrl = "" session.PrevSubUrl = ""
s.PrevViewModel = nil session.PrevViewModel = nil
return return
} }
html, err := s.Provider.GetHtml(prev) html, err := s.Provider.GetHtml(prev)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.PrevSubUrl = "" session.PrevSubUrl = ""
s.PrevViewModel = nil session.PrevViewModel = nil
return return
} }
imagesNext, err := s.AppendImagesToBuf(html) imagesNext, err := s.AppendImagesToBuf(html)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
s.PrevSubUrl = "" session.PrevSubUrl = ""
s.PrevViewModel = nil session.PrevViewModel = nil
return return
} }
@@ -185,21 +184,21 @@ func (s *Server) LoadPrev() {
full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1) full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1)
s.PrevViewModel = &view.ImageViewModel{Images: imagesNext, Title: full} session.PrevViewModel = &view.ImageViewModel{Images: imagesNext, Title: full}
s.PrevSubUrl = prev session.PrevSubUrl = prev
fmt.Println("Loaded prev") fmt.Println("Loaded prev")
} }
func (s *Server) LoadCurr() { func (s *Server) LoadCurr(session *UserSession) {
html, err := s.Provider.GetHtml(s.CurrSubUrl) html, err := s.Provider.GetHtml(session.CurrSubUrl)
if err != nil { if err != nil {
panic(err) panic(err)
} }
imagesCurr, err := s.AppendImagesToBuf(html) imagesCurr, err := s.AppendImagesToBuf(html)
title, chapter, err := s.Provider.GetTitleAndChapter(s.CurrSubUrl) title, chapter, err := s.Provider.GetTitleAndChapter(session.CurrSubUrl)
if err != nil { if err != nil {
title = "Unknown" title = "Unknown"
chapter = "ch_?" chapter = "ch_?"
@@ -207,7 +206,7 @@ func (s *Server) LoadCurr() {
full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1) full := strings.Replace(title, "-", " ", -1) + " - " + strings.Replace(chapter, "_", " ", -1)
s.CurrViewModel = &view.ImageViewModel{Images: imagesCurr, Title: full} session.CurrViewModel = &view.ImageViewModel{Images: imagesCurr, Title: full}
fmt.Println("Loaded current") fmt.Println("Loaded current")
} }

View File

@@ -0,0 +1,31 @@
package utils
import "sync"
type ConcurrentMap[K comparable, Value any] struct {
dirty map[K]Value
count int
mutex *sync.RWMutex
}
func NewConcurrentMap[K comparable, V any]() ConcurrentMap[K, V] {
return ConcurrentMap[K, V]{
dirty: make(map[K]V),
count: 0,
mutex: &sync.RWMutex{},
}
}
func (c *ConcurrentMap[K, Value]) Get(key K) (Value, bool) {
c.mutex.RLock()
defer c.mutex.RUnlock()
val, ok := c.dirty[key]
return val, ok
}
func (c *ConcurrentMap[K, Value]) Set(key K, val Value) {
c.mutex.Lock()
defer c.mutex.Unlock()
c.dirty[key] = val
}

Binary file not shown.