From c251b553a1d3841cc3f5571eda283e29e3e6148d Mon Sep 17 00:00:00 2001 From: Patryk Hegenberg Date: Fri, 24 Nov 2023 20:28:31 +0100 Subject: [PATCH] init commit for ddServer First commit with basic functionality for create a json-file from Input in the html form. --- forms.html | 104 ++++++++++++++++++++ go.mod | 3 + main.go | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 forms.html create mode 100644 go.mod create mode 100644 main.go diff --git a/forms.html b/forms.html new file mode 100644 index 0000000..dfd7a09 --- /dev/null +++ b/forms.html @@ -0,0 +1,104 @@ + + + + + + D&D Monster Form + + + + + +
+ +
+
+

Monster Form

+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+ + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8a6ca08 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module ddServer + +go 1.21.4 diff --git a/main.go b/main.go new file mode 100644 index 0000000..6e60a40 --- /dev/null +++ b/main.go @@ -0,0 +1,277 @@ +package main + +import ( + "encoding/json" + "fmt" + "html/template" + "net/http" + "os" + "strconv" + "sync" + "time" +) + +// Monster struct für die Daten des Monsters +type Monster struct { + Name string `json:"name"` + Source string `json:"source"` + Size []string `json:"size"` + Type string `json:"type"` + Alignment []string `json:"alignment"` + AC []AC `json:"ac"` + HP HP `json:"hp"` + Speed Speed `json:"speed"` + Save Save `json:"save"` + Skill Skill `json:"skill"` + DamageRes []string `json:"damageResistances"` + Senses []string `json:"senses"` + Languages []string `json:"languages"` + CR string `json:"cr"` + Traits []Trait `json:"trait"` + Actions []Action `json:"action"` + Str int `json:"str"` + Dex int `json:"dex"` + Con int `json:"con"` + Int int `json:"int"` + Wis int `json:"wis"` + Cha int `json:"cha"` +} + +type AC struct { + AC int `json:"ac"` + From []string `json:"from"` +} + +type HP struct { + Average int `json:"average"` + Formula string `json:"formula"` +} + +type Speed struct { + Walk int `json:"walk"` +} + +type Save struct { + Dex string `json:"dex"` + Con string `json:"con"` + Wis string `json:"wis"` +} + +type Skill struct { + Perception string `json:"perception"` + Stealth string `json:"stealth"` +} + +type Trait struct { + Name string `json:"name"` + Entries []string `json:"entries"` +} + +type Action struct { + Name string `json:"name"` + Entries []string `json:"entries"` +} + +// Character struct für die Daten des Charakters +type Character struct { + Meta Meta `json:"_meta"` + Monster []Monster `json:"monster"` +} + +// Meta struct für Meta-Informationen +type Meta struct { + Sources []Source `json:"sources"` + DateAdded int64 `json:"dateAdded"` + DateLastModified int64 `json:"dateLastModified"` + DateLastModifiedHash string `json:"_dateLastModifiedHash"` +} + +type Source struct { + Json string `json:"json"` + Abbreviation string `json:"abbreviation"` + Authors []string `json:"authors"` + ConvertedBy []string `json:"convertedBy"` + Version string `json:"version"` +} + +var ( + mu sync.Mutex + chars []Character +) + +func main() { + filename := "" + + http.HandleFunc("/", formHandler(filename)) + http.HandleFunc("/submit", submitHandler(filename)) + + fmt.Println("Server gestartet, erreichbar unter http://localhost:8080") + http.ListenAndServe(":8080", nil) +} + +// formHandler zeigt das Formular an +func formHandler(filename string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + tmpl, err := template.ParseFiles("forms.html") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + tmpl.Execute(w, nil) + } +} + +// submitHandler verarbeitet die Formulardaten +func submitHandler(filename string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + // Formulardaten parsen + err := r.ParseForm() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Monster-Objekt erstellen + filename := r.FormValue("filename") + monster := Monster{ + Name: r.FormValue("name"), + Source: r.FormValue("source"), + Size: []string{r.FormValue("size")}, + Type: r.FormValue("type"), + Alignment: []string{r.FormValue("alignment")}, + AC: []AC{ + { + AC: parseInt(r.FormValue("ac")), + From: []string{r.FormValue("acFrom")}, + }, + }, + HP: HP{ + Average: parseInt(r.FormValue("hpAverage")), + Formula: r.FormValue("hpFormula"), + }, + Speed: Speed{ + Walk: parseInt(r.FormValue("speed")), + }, + Str: parseInt(r.FormValue("str")), + Dex: parseInt(r.FormValue("dex")), + Con: parseInt(r.FormValue("con")), + Int: parseInt(r.FormValue("int")), + Wis: parseInt(r.FormValue("wis")), + Cha: parseInt(r.FormValue("cha")), + Save: Save{ + Dex: r.FormValue("saveDex"), + Con: r.FormValue("saveCon"), + Wis: r.FormValue("saveWis"), + }, + Skill: Skill{ + Perception: r.FormValue("perception"), + Stealth: r.FormValue("stealth"), + }, + DamageRes: []string{r.FormValue("damageRes")}, + Senses: []string{r.FormValue("senses")}, + Languages: []string{r.FormValue("languages")}, + CR: r.FormValue("cr"), + Traits: []Trait{ + { + Name: r.FormValue("traitName"), + Entries: []string{r.FormValue("traitEntry")}, + }, + }, + Actions: []Action{ + { + Name: r.FormValue("actionName"), + Entries: []string{r.FormValue("actionEntry")}, + }, + }, + } + + // Charakter-Objekt erstellen oder aktualisieren + mu.Lock() + defer mu.Unlock() + + char := getOrCreateCharacter(filename) + char.Monster = append(char.Monster, monster) + + // Charakterdaten in JSON umwandeln + charJSON, err := json.Marshal(char) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // JSON-Daten in die Datei schreiben + err = writeToFile(filename, charJSON) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Erfolgsmeldung anzeigen + fmt.Fprintf(w, "Monsterdaten erfolgreich gespeichert in %s: %s", filename, charJSON) + } +} + +// writeToFile schreibt Daten in eine Datei +func writeToFile(filename string, data []byte) error { + file, err := os.Create(filename) + if err != nil { + return err + } + defer file.Close() + + _, err = file.Write(data) + if err != nil { + return err + } + + return nil +} + +// getOrCreateCharacter gibt das aktuelle Charakterobjekt zurück oder erstellt ein neues +func getOrCreateCharacter(filename string) Character { + for _, char := range chars { + if char.Meta.DateLastModified == 0 { + // Ein leeres Charakterobjekt wurde gefunden + return char + } + } + + // Erstelle ein neues Charakterobjekt + now := time.Now().Unix() + newChar := Character{ + Meta: Meta{ + Sources: []Source{ + { + Json: "Malgorgon", + Abbreviation: "MG", + Authors: []string{"Krzysztof"}, + ConvertedBy: []string{"Krzysztof"}, + Version: "unknown", + }, + }, + DateAdded: now, + DateLastModified: now, + DateLastModifiedHash: fmt.Sprintf("%x", now), + }, + Monster: []Monster{}, + } + + chars = append(chars, newChar) + + return newChar +} + +// parseInt konvertiert einen String zu einem Integer und gibt 0 zurück, wenn die Konvertierung fehlschlägt +func parseInt(s string) int { + i, err := strconv.Atoi(s) + if err != nil { + return 0 + } + return i +}