initial commit

This commit is contained in:
stratic-dev
2024-03-12 23:00:01 +00:00
parent 19aadc6e10
commit def2bc3d2c
9 changed files with 157 additions and 23 deletions

3
.gitignore vendored
View File

@@ -7,4 +7,5 @@ savedata/*/
*.exe
*.lnk
*.bat
/docker/db-data
/docker/db-data
sreenshots/*

View File

@@ -9,7 +9,12 @@
],
"PatchServerManifest": "",
"PatchServerFile": "",
"ScreenshotAPIURL": "",
"Screenshots":{
"Enabled":true,
"Host":"127.0.0.1",
"Port":8080,
"OutputDir":"screenshots"
},
"DeleteOnSaveCorruption": false,
"ClientMode": "ZZ",
"QuestCacheExpiry": 300,

View File

@@ -75,7 +75,6 @@ type Config struct {
LoginNotices []string // MHFML string of the login notices displayed
PatchServerManifest string // Manifest patch server override
PatchServerFile string // File patch server override
ScreenshotAPIURL string // Destination for screenshots uploaded to BBS
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
ClientMode string
RealClientMode Mode
@@ -87,16 +86,18 @@ type Config struct {
EarthID int32
EarthMonsters []int32
SaveDumps SaveDumpOptions
DebugOptions DebugOptions
GameplayOptions GameplayOptions
Discord Discord
Commands []Command
Courses []Course
Database Database
Sign Sign
SignV2 SignV2
Channel Channel
Entrance Entrance
Screenshots ScreenshotsOptions
DebugOptions DebugOptions
GameplayOptions GameplayOptions
Discord Discord
Commands []Command
Courses []Course
Database Database
Sign Sign
SignV2 SignV2
Channel Channel
Entrance Entrance
}
type SaveDumpOptions struct {
@@ -105,6 +106,13 @@ type SaveDumpOptions struct {
OutputDir string
}
type ScreenshotsOptions struct {
Enabled bool
Host string // Destination for screenshots uploaded to BBS
Port uint32 // Port for screenshots API
OutputDir string
}
// DebugOptions holds various debug/temporary options for use while developing Erupe.
type DebugOptions struct {
CleanDB bool // Automatically wipes the DB on server reset.

View File

@@ -0,0 +1,13 @@
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;

View File

@@ -8,6 +8,7 @@ import (
)
func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {
//Post Screenshot pauses till this succeedes
pkt := p.(*mhfpacket.MsgMhfGetBbsUserStatus)
bf := byteframe.NewByteFrame()
bf.WriteUint32(200)
@@ -32,10 +33,36 @@ func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {
bf := byteframe.NewByteFrame()
articleToken := token.Generate(40)
bf.WriteUint32(200)
bf.WriteUint32(80)
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.ScreenshotAPIURL, 64, false))
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
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")
}
}

View File

@@ -367,6 +367,15 @@ func (s *Server) DiscordChannelSend(charName string, content string) {
}
}
func (s *Server) DiscordScreenShotSend(charName string, title string, description string) 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
}
return ""
}
func (s *Server) FindSessionByCharID(charID uint32) *Session {
for _, c := range s.Channels {
for _, session := range c.sessions {

View File

@@ -1,10 +1,12 @@
package discordbot
import (
"erupe-ce/config"
"errors"
_config "erupe-ce/config"
"regexp"
"github.com/bwmarrin/discordgo"
"go.uber.org/zap"
"regexp"
)
var Commands = []*discordgo.ApplicationCommand{
@@ -104,14 +106,14 @@ func (bot *DiscordBot) NormalizeDiscordMessage(message string) string {
return result
}
func (bot *DiscordBot) RealtimeChannelSend(message string) (err error) {
func (bot *DiscordBot) RealtimeChannelSend(message string) (messageId string, err error) {
if bot.RelayChannel == nil {
return
return "", errors.New("RelayChannel is nil")
}
_, err = bot.Session.ChannelMessageSend(bot.RelayChannel.ID, message)
msg, err := bot.Session.ChannelMessageSend(bot.RelayChannel.ID, message)
return
return msg.ID, err
}
func ReplaceTextAll(text string, regex *regexp.Regexp, handler func(input string) string) string {

View File

@@ -6,7 +6,12 @@ import (
"errors"
_config "erupe-ce/config"
"erupe-ce/server/channelserver"
"fmt"
"image"
"image/jpeg"
"net/http"
"os"
"path/filepath"
"strings"
"time"
@@ -286,3 +291,66 @@ 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)
return
} else {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// Get File from Request
file, _, err := r.FormFile("img")
if err != nil {
http.Error(w, "No valid file uploaded", http.StatusBadRequest)
return
}
token := r.FormValue("token")
if token == "" {
http.Error(w, "Token not specified cannot continue", http.StatusBadRequest)
return
}
// Validate file
img, _, err := image.Decode(file)
if err != nil {
http.Error(w, "Invalid image file", http.StatusBadRequest)
return
}
dir := filepath.Join(s.erupeConfig.Screenshots.OutputDir)
path := filepath.Join(s.erupeConfig.Screenshots.OutputDir, fmt.Sprintf("%s.jpg", token))
_, err = os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
s.logger.Error("Error writing screenshot, could not create folder")
return
}
} else {
s.logger.Error("Error writing screenshot")
return
}
}
// Create or open the output file
outputFile, err := os.Create(path)
if err != nil {
panic(err)
}
defer outputFile.Close()
// Encode the image and write it to the file
err = jpeg.Encode(outputFile, img, &jpeg.Options{})
if err != nil {
panic(err)
}
if err != nil {
s.logger.Error("Error writing screenshot, could not write file", zap.Error(err))
}
}
}

View File

@@ -2,7 +2,7 @@ package signv2server
import (
"context"
"erupe-ce/config"
_config "erupe-ce/config"
"fmt"
"net/http"
"os"
@@ -52,6 +52,7 @@ func (s *Server) Start() error {
r.HandleFunc("/character/create", s.CreateCharacter)
r.HandleFunc("/character/delete", s.DeleteCharacter)
r.HandleFunc("/character/export", s.ExportSave)
r.HandleFunc("/api/ss/bbs/upload.php", s.ScreenShot)
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)