mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-13 15:34:38 +01:00
initial commit
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ savedata/*/
|
|||||||
*.lnk
|
*.lnk
|
||||||
*.bat
|
*.bat
|
||||||
/docker/db-data
|
/docker/db-data
|
||||||
|
sreenshots/*
|
||||||
@@ -9,7 +9,12 @@
|
|||||||
],
|
],
|
||||||
"PatchServerManifest": "",
|
"PatchServerManifest": "",
|
||||||
"PatchServerFile": "",
|
"PatchServerFile": "",
|
||||||
"ScreenshotAPIURL": "",
|
"Screenshots":{
|
||||||
|
"Enabled":true,
|
||||||
|
"Host":"127.0.0.1",
|
||||||
|
"Port":8080,
|
||||||
|
"OutputDir":"screenshots"
|
||||||
|
},
|
||||||
"DeleteOnSaveCorruption": false,
|
"DeleteOnSaveCorruption": false,
|
||||||
"ClientMode": "ZZ",
|
"ClientMode": "ZZ",
|
||||||
"QuestCacheExpiry": 300,
|
"QuestCacheExpiry": 300,
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ type Config struct {
|
|||||||
LoginNotices []string // MHFML string of the login notices displayed
|
LoginNotices []string // MHFML string of the login notices displayed
|
||||||
PatchServerManifest string // Manifest patch server override
|
PatchServerManifest string // Manifest patch server override
|
||||||
PatchServerFile string // File 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
|
DeleteOnSaveCorruption bool // Attempts to save corrupted data will flag the save for deletion
|
||||||
ClientMode string
|
ClientMode string
|
||||||
RealClientMode Mode
|
RealClientMode Mode
|
||||||
@@ -87,6 +86,8 @@ type Config struct {
|
|||||||
EarthID int32
|
EarthID int32
|
||||||
EarthMonsters []int32
|
EarthMonsters []int32
|
||||||
SaveDumps SaveDumpOptions
|
SaveDumps SaveDumpOptions
|
||||||
|
Screenshots ScreenshotsOptions
|
||||||
|
|
||||||
DebugOptions DebugOptions
|
DebugOptions DebugOptions
|
||||||
GameplayOptions GameplayOptions
|
GameplayOptions GameplayOptions
|
||||||
Discord Discord
|
Discord Discord
|
||||||
@@ -105,6 +106,13 @@ type SaveDumpOptions struct {
|
|||||||
OutputDir string
|
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.
|
// DebugOptions holds various debug/temporary options for use while developing Erupe.
|
||||||
type DebugOptions struct {
|
type DebugOptions struct {
|
||||||
CleanDB bool // Automatically wipes the DB on server reset.
|
CleanDB bool // Automatically wipes the DB on server reset.
|
||||||
|
|||||||
13
schemas/patch-schema/screenshots.sql
Normal file
13
schemas/patch-schema/screenshots.sql
Normal 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;
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {
|
func handleMsgMhfGetBbsUserStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||||
|
//Post Screenshot pauses till this succeedes
|
||||||
pkt := p.(*mhfpacket.MsgMhfGetBbsUserStatus)
|
pkt := p.(*mhfpacket.MsgMhfGetBbsUserStatus)
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
bf.WriteUint32(200)
|
bf.WriteUint32(200)
|
||||||
@@ -32,10 +33,36 @@ func handleMsgMhfApplyBbsArticle(s *Session, p mhfpacket.MHFPacket) {
|
|||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
articleToken := token.Generate(40)
|
articleToken := token.Generate(40)
|
||||||
bf.WriteUint32(200)
|
bf.WriteUint32(200)
|
||||||
bf.WriteUint32(80)
|
bf.WriteUint32(s.server.erupeConfig.Screenshots.Port)
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
bf.WriteUint32(0)
|
bf.WriteUint32(0)
|
||||||
bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false))
|
bf.WriteBytes(stringsupport.PaddedString(articleToken, 64, false))
|
||||||
bf.WriteBytes(stringsupport.PaddedString(s.server.erupeConfig.ScreenshotAPIURL, 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())
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
func (s *Server) FindSessionByCharID(charID uint32) *Session {
|
||||||
for _, c := range s.Channels {
|
for _, c := range s.Channels {
|
||||||
for _, session := range c.sessions {
|
for _, session := range c.sessions {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package discordbot
|
package discordbot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"erupe-ce/config"
|
"errors"
|
||||||
|
_config "erupe-ce/config"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"regexp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Commands = []*discordgo.ApplicationCommand{
|
var Commands = []*discordgo.ApplicationCommand{
|
||||||
@@ -104,14 +106,14 @@ func (bot *DiscordBot) NormalizeDiscordMessage(message string) string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bot *DiscordBot) RealtimeChannelSend(message string) (err error) {
|
func (bot *DiscordBot) RealtimeChannelSend(message string) (messageId string, err error) {
|
||||||
if bot.RelayChannel == nil {
|
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 {
|
func ReplaceTextAll(text string, regex *regexp.Regexp, handler func(input string) string) string {
|
||||||
|
|||||||
@@ -6,7 +6,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
_config "erupe-ce/config"
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -286,3 +291,66 @@ func (s *Server) ExportSave(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(save)
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package signv2server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"erupe-ce/config"
|
_config "erupe-ce/config"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -52,6 +52,7 @@ func (s *Server) Start() error {
|
|||||||
r.HandleFunc("/character/create", s.CreateCharacter)
|
r.HandleFunc("/character/create", s.CreateCharacter)
|
||||||
r.HandleFunc("/character/delete", s.DeleteCharacter)
|
r.HandleFunc("/character/delete", s.DeleteCharacter)
|
||||||
r.HandleFunc("/character/export", s.ExportSave)
|
r.HandleFunc("/character/export", s.ExportSave)
|
||||||
|
r.HandleFunc("/api/ss/bbs/upload.php", s.ScreenShot)
|
||||||
handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r)
|
handler := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}))(r)
|
||||||
s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, handler)
|
s.httpServer.Handler = handlers.LoggingHandler(os.Stdout, handler)
|
||||||
s.httpServer.Addr = fmt.Sprintf(":%d", s.erupeConfig.SignV2.Port)
|
s.httpServer.Addr = fmt.Sprintf(":%d", s.erupeConfig.SignV2.Port)
|
||||||
|
|||||||
Reference in New Issue
Block a user