From 3797438ca2c13d3ebf5889cbbf815d645f0d06e3 Mon Sep 17 00:00:00 2001 From: stratic-dev Date: Fri, 15 Mar 2024 00:54:18 +0000 Subject: [PATCH] No database --- .gitignore | 2 +- config.json | 3 +- config/config.go | 9 +-- schemas/patch-schema/screenshots.sql | 13 ---- server/channelserver/handlers_bbs.go | 47 +++++-------- server/channelserver/sys_channel_server.go | 9 ++- server/discordbot/discord_bot.go | 10 ++- server/signv2server/endpoints.go | 81 ++++++++++++++++------ server/signv2server/signv2_server.go | 1 + 9 files changed, 94 insertions(+), 81 deletions(-) delete mode 100644 schemas/patch-schema/screenshots.sql diff --git a/.gitignore b/.gitignore index 493cbb0f6..5b569b1c2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,4 @@ savedata/*/ *.lnk *.bat /docker/db-data -sreenshots/* \ No newline at end of file +screenshots/* \ No newline at end of file diff --git a/config.json b/config.json index 2943915ba..a4ef568cf 100644 --- a/config.json +++ b/config.json @@ -13,7 +13,8 @@ "Enabled":true, "Host":"127.0.0.1", "Port":8080, - "OutputDir":"screenshots" + "OutputDir":"screenshots", + "UploadQuality":100 }, "DeleteOnSaveCorruption": false, "ClientMode": "ZZ", diff --git a/config/config.go b/config/config.go index c88bd3912..6e86c60ed 100644 --- a/config/config.go +++ b/config/config.go @@ -107,10 +107,11 @@ type SaveDumpOptions struct { } type ScreenshotsOptions struct { - Enabled bool - Host string // Destination for screenshots uploaded to BBS - Port uint32 // Port for screenshots API - OutputDir string + Enabled bool + Host string // Destination for screenshots uploaded to BBS + Port uint32 // Port for screenshots API + OutputDir string + UploadQuality int //Determines the upload quality to the server } // DebugOptions holds various debug/temporary options for use while developing Erupe. diff --git a/schemas/patch-schema/screenshots.sql b/schemas/patch-schema/screenshots.sql deleted file mode 100644 index 345fcda13..000000000 --- a/schemas/patch-schema/screenshots.sql +++ /dev/null @@ -1,13 +0,0 @@ -BEGIN; - -CREATE TABLE public.screenshots -( - id serial PRIMARY KEY, - article_id TEXT NOT NULL, - discord_message_id TEXT, - char_id integer NOT NULL, - title TEXT NOT NULL, - description TEXT NOT NULL, - discord_img_url TEXT, - ); -END; \ No newline at end of file diff --git a/server/channelserver/handlers_bbs.go b/server/channelserver/handlers_bbs.go index 69abc542d..d991ee67a 100644 --- a/server/channelserver/handlers_bbs.go +++ b/server/channelserver/handlers_bbs.go @@ -7,62 +7,47 @@ import ( "erupe-ce/network/mhfpacket" ) +// Handler BBS handles all the interactions with the for the screenshot sending to bulitin board functionality. For it to work it requires the API to be hosted somehwere. This implementation supports discord. + +// Checks the status of the user to see if they can use Bulitin Board yet func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) { //Post Screenshot pauses till this succeedes pkt := p.(*mhfpacket.MsgMhfGetBbsUserStatus) bf := byteframe.NewByteFrame() - bf.WriteUint32(200) + bf.WriteUint32(200) //HTTP Status Codes //200 Success //404 You wont be able to post for a certain amount of time after creating your character //401/500 A error occured server side bf.WriteUint32(0) bf.WriteUint32(0) bf.WriteUint32(0) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } +// Checks the status of Bultin Board Server to see if authenticated func handleMsgMhfGetBbsSnsStatus(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfGetBbsSnsStatus) bf := byteframe.NewByteFrame() - bf.WriteUint32(200) - bf.WriteUint32(401) - bf.WriteUint32(401) + bf.WriteUint32(200) //200 Success //4XX Authentication has expired Please re-authenticate //5XX + bf.WriteUint32(401) //unk http status? + bf.WriteUint32(401) //unk http status? bf.WriteUint32(0) doAckBufSucceed(s, pkt.AckHandle, bf.Data()) } +// Tells the game client what host port and gives the bultin board article a token func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) { pkt := p.(*mhfpacket.MsgMhfApplyBbsArticle) bf := byteframe.NewByteFrame() articleToken := token.Generate(40) - bf.WriteUint32(200) + + bf.WriteUint32(200) //http status //200 success //4XX An error occured server side bf.WriteUint32(s.server.erupeConfig.Screenshots.Port) bf.WriteUint32(0) bf.WriteUint32(0) bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false)) bf.WriteBytes(stringsupport.PaddedString(s.server.erupeConfig.Screenshots.Host, 64, false)) - - if s.server.erupeConfig.SaveDumps.Enabled && s.server.erupeConfig.Discord.Enabled { - messageId := s.server.DiscordScreenShotSend(pkt.Name, pkt.Title, pkt.Description) // TODO: send and get back message id store in db - - _, err := s.server.db.Exec("INSERT INTO public.screenshots (article_id,discord_message_id,char_id,title,description) VALUES ($1,$2,$3,$4,$5)", articleToken, messageId, s.charID, pkt.Title, pkt.Description) - if err != nil { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - } else { - - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - s.server.BroadcastChatMessage("Screenshot has been sent to discord") - - } - - } else if s.server.erupeConfig.SaveDumps.Enabled { - _, err := s.server.db.Exec("INSERT INTO public.screenshots (article_id,char_id,title,description) VALUES ($1,$2,$3,$4)", articleToken, s.charID, pkt.Title, pkt.Description) - if err != nil { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - } else { - s.server.BroadcastChatMessage("Screenshot has been sent to server") - doAckBufSucceed(s, pkt.AckHandle, bf.Data()) - - } - } else { - doAckBufFail(s, pkt.AckHandle, make([]byte, 4)) - s.server.BroadcastChatMessage("No destination for screenshots have been configured by the host") + //pkt.unk1[3] == Changes sometimes? + if s.server.erupeConfig.Screenshots.Enabled && s.server.erupeConfig.Discord.Enabled { + s.server.DiscordScreenShotSend(pkt.Name, pkt.Title, pkt.Description, articleToken) } + doAckBufSucceed(s, pkt.AckHandle, bf.Data()) + } diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 6d2c7c39d..a0d1fe1b7 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -367,13 +367,12 @@ func (s *Server) DiscordChannelSend(charName string, content string) { } } -func (s *Server) DiscordScreenShotSend(charName string, title string, description string) string { +func (s *Server) DiscordScreenShotSend(charName string, title string, description string, articleToken string) { if s.erupeConfig.Discord.Enabled && s.discordBot != nil { - message := fmt.Sprintf("**%s**: %s - %s", charName, title, description) - mesageId, _ := s.discordBot.RealtimeChannelSend(message) - return mesageId + imageUrl := fmt.Sprintf("%s:%d/api/ss/bbs/%s", s.erupeConfig.Screenshots.Host, s.erupeConfig.Screenshots.Port, articleToken) + message := fmt.Sprintf("**%s**: %s - %s %s", charName, title, description, imageUrl) + s.discordBot.RealtimeChannelSend(message) } - return "" } func (s *Server) FindSessionByCharID(charID uint32) *Session { diff --git a/server/discordbot/discord_bot.go b/server/discordbot/discord_bot.go index 9c824684f..303cbc630 100644 --- a/server/discordbot/discord_bot.go +++ b/server/discordbot/discord_bot.go @@ -1,7 +1,6 @@ package discordbot import ( - "errors" _config "erupe-ce/config" "regexp" @@ -106,16 +105,15 @@ func (bot *DiscordBot) NormalizeDiscordMessage(message string) string { return result } -func (bot *DiscordBot) RealtimeChannelSend(message string) (messageId string, err error) { +func (bot *DiscordBot) RealtimeChannelSend(message string) (err error) { if bot.RelayChannel == nil { - return "", errors.New("RelayChannel is nil") + return } - msg, err := bot.Session.ChannelMessageSend(bot.RelayChannel.ID, message) + _, err = bot.Session.ChannelMessageSend(bot.RelayChannel.ID, message) - return msg.ID, err + return } - func ReplaceTextAll(text string, regex *regexp.Regexp, handler func(input string) string) string { result := regex.ReplaceAllFunc([]byte(text), func(s []byte) []byte { input := regex.ReplaceAllString(string(s), `$1`) diff --git a/server/signv2server/endpoints.go b/server/signv2server/endpoints.go index 7647ce743..8200cd824 100644 --- a/server/signv2server/endpoints.go +++ b/server/signv2server/endpoints.go @@ -3,18 +3,21 @@ package signv2server import ( "database/sql" "encoding/json" + "encoding/xml" "errors" _config "erupe-ce/config" "erupe-ce/server/channelserver" "fmt" "image" "image/jpeg" + "io" "net/http" "os" "path/filepath" "strings" "time" + "github.com/gorilla/mux" "github.com/lib/pq" "go.uber.org/zap" "golang.org/x/crypto/bcrypt" @@ -291,35 +294,63 @@ func (s *Server) ExportSave(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") json.NewEncoder(w).Encode(save) } - -func (s *Server) ScreenShot(w http.ResponseWriter, r *http.Request) { - if !s.erupeConfig.SaveDumps.Enabled { - http.Error(w, "Screenshots not enabled in Config", http.StatusBadRequest) - +func (s *Server) ScreenShotGet(w http.ResponseWriter, r *http.Request) { + // Get the 'id' parameter from the URL + vars := mux.Vars(r) + id := vars["id"] + // Open the image file + path := filepath.Join(s.erupeConfig.Screenshots.OutputDir, fmt.Sprintf("%s.jpg", id)) + file, err := os.Open(path) + if err != nil { + http.Error(w, "Image not found", http.StatusNotFound) return + } + defer file.Close() + // Set content type header to image/jpeg + w.Header().Set("Content-Type", "image/jpeg") + // Copy the image content to the response writer + if _, err := io.Copy(w, file); err != nil { + http.Error(w, "Unable to send image", http.StatusInternalServerError) + return + } +} +func (s *Server) ScreenShot(w http.ResponseWriter, r *http.Request) { + + // Create a struct representing the XML result + type Result struct { + XMLName xml.Name `xml:"result"` + Code string `xml:"code"` + } + // Set the Content-Type header to specify that the response is in XML format + w.Header().Set("Content-Type", "text/xml") + result := Result{Code: "200"} + + if !s.erupeConfig.Screenshots.Enabled { + result = Result{Code: "400"} + } else { if r.Method != http.MethodPost { - http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) - return + result = Result{Code: "405"} + } // Get File from Request file, _, err := r.FormFile("img") if err != nil { - http.Error(w, "No valid file uploaded", http.StatusBadRequest) - return + result = Result{Code: "400"} + } token := r.FormValue("token") if token == "" { - http.Error(w, "Token not specified cannot continue", http.StatusBadRequest) - return + result = Result{Code: "400"} + } // Validate file img, _, err := image.Decode(file) if err != nil { - http.Error(w, "Invalid image file", http.StatusBadRequest) - return + result = Result{Code: "400"} + } dir := filepath.Join(s.erupeConfig.Screenshots.OutputDir) @@ -330,27 +361,37 @@ func (s *Server) ScreenShot(w http.ResponseWriter, r *http.Request) { err = os.MkdirAll(dir, os.ModePerm) if err != nil { s.logger.Error("Error writing screenshot, could not create folder") - return + result = Result{Code: "500"} } } else { s.logger.Error("Error writing screenshot") - return + result = Result{Code: "500"} } } // Create or open the output file outputFile, err := os.Create(path) if err != nil { - panic(err) + result = Result{Code: "500"} } defer outputFile.Close() // Encode the image and write it to the file - err = jpeg.Encode(outputFile, img, &jpeg.Options{}) - if err != nil { - panic(err) - } + err = jpeg.Encode(outputFile, img, &jpeg.Options{Quality: s.erupeConfig.Screenshots.UploadQuality}) if err != nil { s.logger.Error("Error writing screenshot, could not write file", zap.Error(err)) + result = Result{Code: "500"} + } + } + // Marshal the struct into XML + xmlData, err := xml.Marshal(result) + if err != nil { + http.Error(w, "Unable to marshal XML", http.StatusInternalServerError) + return + } + + // Write the XML response with a 200 status code + w.WriteHeader(http.StatusOK) + w.Write(xmlData) } diff --git a/server/signv2server/signv2_server.go b/server/signv2server/signv2_server.go index 3b278a3a7..32c852e30 100644 --- a/server/signv2server/signv2_server.go +++ b/server/signv2server/signv2_server.go @@ -53,6 +53,7 @@ func (s *Server) Start() error { r.HandleFunc("/character/delete", s.DeleteCharacter) r.HandleFunc("/character/export", s.ExportSave) r.HandleFunc("/api/ss/bbs/upload.php", s.ScreenShot) + r.HandleFunc("/api/ss/bbs/{id}", s.ScreenShotGet) handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r) s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, handler) s.httpServer.Addr = fmt.Sprintf(":%d", s.erupeConfig.SignV2.Port)