From 469d1dfcb33d88d6abbb4396241e78e7f676939a Mon Sep 17 00:00:00 2001 From: Joseph Manley Date: Sun, 27 Dec 2020 04:27:57 -0500 Subject: [PATCH 1/4] Start development work on webserver runtime --- go.mod | 3 ++- go.sum | 4 ++++ main.go | 12 ++++++++-- runtime/webserver.go | 56 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 runtime/webserver.go diff --git a/go.mod b/go.mod index ed4c485..e1cf770 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/josephbmanley/OpenSkins go 1.13 require ( - github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227061123-22199a5c0ab9 + github.com/gorilla/mux v1.8.0 + github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a github.com/sirupsen/logrus v1.7.0 ) diff --git a/go.sum b/go.sum index 3758d83..29c9d2c 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/josephbmanley/OpenSkins-Common v0.0.0-20201226022245-12099a28475a h1:bW/ahOovqRP2r1Ynp4WXxrOCiHq1vqye8RFyYLIZ6hg= github.com/josephbmanley/OpenSkins-Common v0.0.0-20201226022245-12099a28475a/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227051624-01b75eb56779 h1:ArCBRyblBk/x0BGgNu6gJ7j7kNvn91K7OmpOHpHUwAs= @@ -10,6 +12,8 @@ github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227060121-852c176c7219 h1: github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227060121-852c176c7219/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227061123-22199a5c0ab9 h1:rEfQZyiAKIKchefT4uUGojwLVPDEylORTOU1/l+VEQU= github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227061123-22199a5c0ab9/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= +github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a h1:BVoRW4lVzSDTUGanOxoKnPIvVcRhY5v6h3j0pOlV/DY= +github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= diff --git a/main.go b/main.go index 3077421..982d552 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,14 @@ package main import ( "fmt" "github.com/josephbmanley/OpenSkins/pluginmanager" + "github.com/josephbmanley/OpenSkins/runtime" log "github.com/sirupsen/logrus" "os" "plugin" ) +var appRuntime = "webserver" + const plugindirectory = "./plugins" func main() { @@ -37,7 +40,12 @@ func main() { os.Exit(1) } - log.Fatalln("Runtime is currently not implemented!") - os.Exit(1) + switch appRuntime { + case "webserver": + runtime.StartWebserver() + default: + log.Fatalln("Runtime is currently not implemented!") + os.Exit(1) + } } diff --git a/runtime/webserver.go b/runtime/webserver.go new file mode 100644 index 0000000..87eeaa3 --- /dev/null +++ b/runtime/webserver.go @@ -0,0 +1,56 @@ +package runtime + +import ( + "encoding/json" + "fmt" + "github.com/gorilla/mux" + "github.com/josephbmanley/OpenSkins-Common/datastore" + "log" + "net/http" +) + +var activeSkinstore datastore.Skinstore +var activeUserstore datastore.Userstore + +func healthCheck(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Service is healthy!") +} + +func getCharacter(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + userID := vars["user"] + charID := vars["char"] + + user, err := activeUserstore.GetUser(userID) + + // Check if there was an error getting the user + if err != nil { + log.Panicf("An error occured when getting a character: %v", err.Error()) + w.WriteHeader(500) + return + } + + // Check if user exists + if user == nil { + w.WriteHeader(404) + return + } + + for _, character := range user.Characters { + if character.UID == charID { + json.NewEncoder(w).Encode(character) + return + } + } + + w.WriteHeader(404) + return +} + +// StartWebserver starts the webserver +func StartWebserver() { + myRouter := mux.NewRouter().StrictSlash(true) + myRouter.HandleFunc("/health", healthCheck) + myRouter.HandleFunc("/get/character/{user}/{char}", getCharacter) + log.Fatal(http.ListenAndServe(":8081", myRouter)) +} From ac6f46345a999fde8dceaef5482e21875caf35d3 Mon Sep 17 00:00:00 2001 From: Joseph Manley Date: Thu, 28 Jan 2021 07:20:49 -0500 Subject: [PATCH 2/4] Intergrate vscode and gmake --- .gitignore | 6 ++-- .vscode/launch.json | 15 +++++++++ .vscode/tasks.json | 35 +++++++++++++++++++ Makefile | 82 +++++++++++++++++++++++++++++++++++++++++++++ main.go | 3 +- 5 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 8d475c0..629e407 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ *.dll *.so *.dylib +bin/ +.env/ # Test binary, built with `go test -c` *.test @@ -11,6 +13,6 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out -# Dependency directories (remove the comment below to include it) -# vendor/ +# Dependency directories +vendor/ plugins/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8fef2d3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch executable", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "${workspaceRoot}/bin/OpenSkins", + "preLaunchTask": "compile", + "internalConsoleOptions": "openOnSessionStart" + } + ] +} + diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..286bf2f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,35 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "compile", + "type": "shell", + "command": "make compile" + }, + { + "label": "install", + "type": "shell", + "command": "make install" + }, + { + "label": "clean", + "type": "shell", + "command": "make clean" + }, + { + "label": "build", + "type": "shell", + "command": "make build" + }, + { + "label": "run", + "type": "shell", + "command": "make run" + }, + { + "label": "test", + "type": "shell", + "command": "make test" + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6e26e7a --- /dev/null +++ b/Makefile @@ -0,0 +1,82 @@ +#include .env + +PROJECTNAME="OpenSkins" + +# Go related variables. +GOBASE=$(shell pwd) +GOPATH=$(GOBASE)/vendor:$(GOBASE):/home/azer/code/golang # You can remove or change the path after last colon. +GOBIN=$(GOBASE)/bin +GOFILES=$(wildcard *.go) + +# Redirect error output to a file, so we can show it in development mode. +STDERR=/tmp/.$(PROJECTNAME)-stderr.txt + +# PID file will store the server process id when it's running on development mode +PID=/tmp/.$(PROJECTNAME)-api-server.pid + +# Make is verbose in Linux. Make it silent. +MAKEFLAGS += --silent + +go-compile: go-clean go-get go-build + +go-build: + @echo " > Building binary..." + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) + +go-generate: + @echo " > Generating dependency files..." + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) + +go-get: + @echo " > Checking if there is any missing dependencies..." + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) + +go-install: + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) + +go-clean: + @echo " > Cleaning build cache" + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean + +go-test: + @echo " > Running tests..." + @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go test + +go-run: + @echo " > Running ${PROJECTNAME}" + @-(cd $(GOBIN); ./$(PROJECTNAME)) + + +## install: downloads and installs dependencies +install: go-get + +## clean: test +clean: + @(MAKEFILE) go-clean + +## compile: cleans project, installs dependencies, and builds project +compile: + @-touch $(STDERR) + @-rm $(STDERR) + @-$(MAKE) -s go-compile 2> $(STDERR) + @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2 + +## watch: Runs go clean +watch: + @yolo -i . -e vendor -e bin -c $(run) + +## build: Runs go build +build: go-build + +## run: Compiles and executes project binary +run: go-compile go-run + +## test: Run unit tests +test: go-test + +## help: Displays help text for make commands +.DEFAULT_GOAL := help +all: help +help: Makefile + @echo " Choose a command run in "$(PROJECTNAME)":" + @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' \ No newline at end of file diff --git a/main.go b/main.go index 982d552..0defc5d 100644 --- a/main.go +++ b/main.go @@ -17,7 +17,8 @@ func main() { pluginFiles, err := pluginmanager.GetPlugins(plugindirectory) if err != nil { - log.Warningln(fmt.Sprintf("Failed to read plugins directory: %v", err.Error())) + log.Fatalln(fmt.Sprintf("Failed to read plugins directory: %v", err.Error())) + os.Exit(1) } loadedPlugins := []*plugin.Plugin{} From f17f3d160c3bf664e60756f7adeb52298c77ff4e Mon Sep 17 00:00:00 2001 From: Joseph Manley Date: Thu, 28 Jan 2021 08:02:13 -0500 Subject: [PATCH 3/4] Webserver runtime takes port as variable --- main.go | 2 +- runtime/webserver.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index 0defc5d..a7f172d 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func main() { switch appRuntime { case "webserver": - runtime.StartWebserver() + runtime.StartWebserver(8081) default: log.Fatalln("Runtime is currently not implemented!") os.Exit(1) diff --git a/runtime/webserver.go b/runtime/webserver.go index 87eeaa3..423d32e 100644 --- a/runtime/webserver.go +++ b/runtime/webserver.go @@ -48,9 +48,9 @@ func getCharacter(w http.ResponseWriter, r *http.Request) { } // StartWebserver starts the webserver -func StartWebserver() { +func StartWebserver(port int) { myRouter := mux.NewRouter().StrictSlash(true) myRouter.HandleFunc("/health", healthCheck) myRouter.HandleFunc("/get/character/{user}/{char}", getCharacter) - log.Fatal(http.ListenAndServe(":8081", myRouter)) + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), myRouter)) } From 05ad9a50c3712774a35e81ac97dfaf896ce114ce Mon Sep 17 00:00:00 2001 From: Joseph Manley Date: Fri, 29 Jan 2021 23:19:27 -0500 Subject: [PATCH 4/4] Intial webserver runtime --- .vscode/launch.json | 11 ++- .vscode/tasks.json | 5 + Makefile | 32 +++++-- go.mod | 6 +- go.sum | 31 ++++--- main.go | 2 +- pluginmanager/skinstore.go | 2 + runtime/webserver.go | 181 ++++++++++++++++++++++++++++++++++++- 8 files changed, 240 insertions(+), 30 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8fef2d3..c021d3e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,13 +2,22 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch executable", + "name": "Build & Launch", "type": "go", "request": "launch", "mode": "exec", "program": "${workspaceRoot}/bin/OpenSkins", "preLaunchTask": "compile", "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": "Build & Launch - Standalone", + "type": "go", + "request": "launch", + "mode": "exec", + "program": "${workspaceRoot}/bin/OpenSkins", + "preLaunchTask": "standalone", + "internalConsoleOptions": "openOnSessionStart" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 286bf2f..901c31f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -30,6 +30,11 @@ "label": "test", "type": "shell", "command": "make test" + }, + { + "label": "standalone", + "type": "shell", + "command": "make standalone" } ] } \ No newline at end of file diff --git a/Makefile b/Makefile index 6e26e7a..3260613 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,11 @@ #include .env PROJECTNAME="OpenSkins" +STANDALONE_LOCATION="../OpenSkins-Standalone-Plugin/bin/OpenSkins-Standalone-Plugin" # Go related variables. GOBASE=$(shell pwd) -GOPATH=$(GOBASE)/vendor:$(GOBASE):/home/azer/code/golang # You can remove or change the path after last colon. +GOPATH=$(GOBASE)/vendor:$(GOBASE) GOBIN=$(GOBASE)/bin GOFILES=$(wildcard *.go) @@ -21,36 +22,41 @@ go-compile: go-clean go-get go-build go-build: @echo " > Building binary..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) + @go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) go-generate: @echo " > Generating dependency files..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) + @go generate $(generate) go-get: @echo " > Checking if there is any missing dependencies..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) + @go get $(get) go-install: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) + @echo " > Running go install..." + @go install $(GOFILES) go-clean: @echo " > Cleaning build cache" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean + @go clean go-test: @echo " > Running tests..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go test + @go test go-run: @echo " > Running ${PROJECTNAME}" @-(cd $(GOBIN); ./$(PROJECTNAME)) +openskins-common: + @echo " > Updating common library..." + @go get -u github.com/josephbmanley/OpenSkins-Common + ## install: downloads and installs dependencies -install: go-get +install: openskins-common go-get -## clean: test +## clean: Runs go clean clean: @(MAKEFILE) go-clean @@ -61,7 +67,7 @@ compile: @-$(MAKE) -s go-compile 2> $(STDERR) @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2 -## watch: Runs go clean +## watch: Runs command on code update watch: @yolo -i . -e vendor -e bin -c $(run) @@ -74,6 +80,12 @@ run: go-compile go-run ## test: Run unit tests test: go-test +## standalone: Compile project & install standalone plugin *REQUIRES BUILD IN `../OpenSkins-Standalone-Plugin/bin`* +standalone: compile + @mkdir -p ./bin/plugins + @rm -f ./bin/plugins/standalone.so + @cp $(STANDALONE_LOCATION) ./bin/plugins/standalone.so + ## help: Displays help text for make commands .DEFAULT_GOAL := help all: help diff --git a/go.mod b/go.mod index e1cf770..3827c05 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,10 @@ go 1.13 require ( github.com/gorilla/mux v1.8.0 - github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a + github.com/josephbmanley/OpenSkins-Common v0.0.1 github.com/sirupsen/logrus v1.7.0 + github.com/stretchr/objx v0.3.0 // indirect + github.com/stretchr/testify v1.7.0 // indirect + golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 29c9d2c..cfc2f51 100644 --- a/go.sum +++ b/go.sum @@ -1,24 +1,31 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201226022245-12099a28475a h1:bW/ahOovqRP2r1Ynp4WXxrOCiHq1vqye8RFyYLIZ6hg= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201226022245-12099a28475a/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227051624-01b75eb56779 h1:ArCBRyblBk/x0BGgNu6gJ7j7kNvn91K7OmpOHpHUwAs= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227051624-01b75eb56779/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227052902-2d6c9664ec1e h1:5nRhRlgg/IX2yp4R/NDG1ku65ldkl5/LKxZxg4UcWw4= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227052902-2d6c9664ec1e/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227060121-852c176c7219 h1:PHEi0kL7sC2ERY34grA1bsObqXRcZzMZVDisCB4xm3Q= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227060121-852c176c7219/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227061123-22199a5c0ab9 h1:rEfQZyiAKIKchefT4uUGojwLVPDEylORTOU1/l+VEQU= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227061123-22199a5c0ab9/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a h1:BVoRW4lVzSDTUGanOxoKnPIvVcRhY5v6h3j0pOlV/DY= -github.com/josephbmanley/OpenSkins-Common v0.0.0-20201227072620-649a4ef8820a/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= +github.com/josephbmanley/OpenSkins-Common v0.0.0-20210129235549-eea81c7820d0 h1:nrARrp3he8wkT1P+ryMjJbMxhlwjmVWLhDWvxU5iHoo= +github.com/josephbmanley/OpenSkins-Common v0.0.0-20210129235549-eea81c7820d0/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= +github.com/josephbmanley/OpenSkins-Common v0.0.1 h1:rOvP3YMgx1XNJ9JQU76AMWkypiWKHQw4Wxr76dhsMME= +github.com/josephbmanley/OpenSkins-Common v0.0.1/go.mod h1:xmRLNQLOMLqiQ2hzP81mdsNbu6ZxyLozoVWaR2A0BMY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= +github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index a7f172d..4d74132 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func main() { switch appRuntime { case "webserver": - runtime.StartWebserver(8081) + runtime.StartWebserver(8080) // Start on port 8080 default: log.Fatalln("Runtime is currently not implemented!") os.Exit(1) diff --git a/pluginmanager/skinstore.go b/pluginmanager/skinstore.go index 1461d2a..a39e1cc 100644 --- a/pluginmanager/skinstore.go +++ b/pluginmanager/skinstore.go @@ -16,6 +16,7 @@ var LoadedSkinstores []datastore.Skinstore = []datastore.Skinstore{} func LoadSkinstores(plugins []*plugin.Plugin) error { for _, plugin := range plugins { + log.Debug("Looking for skinstore in plugin...") symSkinstore, err := plugin.Lookup("SkinstoreModule") if err != nil { @@ -33,6 +34,7 @@ func LoadSkinstores(plugins []*plugin.Plugin) error { return err } + log.Info("Loaded new skinstore!") LoadedSkinstores = append(LoadedSkinstores, skinstore) } return nil diff --git a/runtime/webserver.go b/runtime/webserver.go index 423d32e..ab48575 100644 --- a/runtime/webserver.go +++ b/runtime/webserver.go @@ -1,10 +1,14 @@ package runtime import ( + "bytes" "encoding/json" "fmt" "github.com/gorilla/mux" "github.com/josephbmanley/OpenSkins-Common/datastore" + "github.com/josephbmanley/OpenSkins-Common/datatypes" + "github.com/josephbmanley/OpenSkins/pluginmanager" + "io" "log" "net/http" ) @@ -17,6 +21,9 @@ func healthCheck(w http.ResponseWriter, r *http.Request) { } func getCharacter(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(501) + return + vars := mux.Vars(r) userID := vars["user"] charID := vars["char"] @@ -25,7 +32,7 @@ func getCharacter(w http.ResponseWriter, r *http.Request) { // Check if there was an error getting the user if err != nil { - log.Panicf("An error occured when getting a character: %v", err.Error()) + log.Printf("An error occured when getting a character: %v", err.Error()) w.WriteHeader(500) return } @@ -36,21 +43,185 @@ func getCharacter(w http.ResponseWriter, r *http.Request) { return } + // Find character for _, character := range user.Characters { if character.UID == charID { - json.NewEncoder(w).Encode(character) - return + json.NewEncoder(w).Encode(character) // Return character Json + return // Return 200 } } + // Return 404 w.WriteHeader(404) return } +func createCharacter(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(501) + return + + vars := mux.Vars(r) + userID := vars["user"] + charID := vars["char"] + + user, err := activeUserstore.GetUser(userID) + + // Check if there was an error getting the user + if err != nil { + log.Printf("CREATE CHARACTER - Failed to get user: %v", err.Error()) + w.WriteHeader(500) + return + } + + // Check if user exists + if user == nil { + w.WriteHeader(400) + w.Write([]byte("User does not exist!")) + return + } + + // Check if character already exists + for _, character := range user.Characters { + if character.UID == charID { + w.WriteHeader(400) + w.Write([]byte("Character already exists!")) + return + } + } + + newCharacter := datatypes.Character{ + UID: charID, + Skin: datatypes.Skin{ + UID: "none", + }, + } + + // Add character to user object + user.Characters = append(user.Characters, newCharacter) + err = activeUserstore.SetUser(user) + + if err != nil { + log.Printf("CREATE CHARACTER - Failed to set user %v", err.Error()) + w.WriteHeader(500) + } + + return +} + +func getSkin(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + skinID := vars["skin"] + + // Get skin + skin, err := activeSkinstore.GetSkin(skinID) + if err != nil { + log.Printf("GET SKIN - Failed to get skin %v", err.Error()) + w.WriteHeader(500) + } + + // Check if skin exists + if skin == nil { + w.WriteHeader(404) + return + } + + json.NewEncoder(w).Encode(skin) // Return skin Json + return // Return 200 +} + +func createSkin(w http.ResponseWriter, r *http.Request) { + + vars := mux.Vars(r) + skinID := vars["skin"] + + // Lookup skin object + skin, err := activeSkinstore.GetSkin(skinID) + if err != nil { + log.Printf("CREATE SKIN - Failed to get skin: %v", err.Error()) + w.WriteHeader(500) + return + } + + // Check if skin exists + if skin != nil { + w.WriteHeader(400) + w.Write([]byte("Skin already exists!")) + return + } + + // Load skin data from request + skinBytes, err := readfile(r, "skin") + if err != nil { + log.Printf("CREATE SKIN - Failed to read upload: %v", err.Error()) + } + + // Verify data exists + if skinBytes == nil { + w.WriteHeader(400) + w.Write([]byte("Missing skin data!")) + return + } + + // Create new skin object + err = activeSkinstore.AddSkin(skinID, skinBytes) + + // Validate skin creation + if err != nil { + log.Printf("CREATE SKIN - Failed to add skin: %v", err.Error()) + w.WriteHeader(500) + return + } + + return // Return 200 +} + +// Helper function to read a file from a request form +func readfile(r *http.Request, fileName string) ([]byte, error) { + + err := r.ParseMultipartForm(32 << 20) // Limit upload size + if err != nil { + return nil, err + } + + var buf bytes.Buffer + + file, _, err := r.FormFile(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + // Copy the file data to my buffer + _, err = io.Copy(&buf, file) + if err != nil { + return nil, err + } + + contents := buf.Bytes() // Get data + buf.Reset() // Clear buffer + + return contents, nil +} + // StartWebserver starts the webserver func StartWebserver(port int) { + + activeSkinstore = pluginmanager.LoadedSkinstores[0] // Load first skinstore + + // Intialize router myRouter := mux.NewRouter().StrictSlash(true) - myRouter.HandleFunc("/health", healthCheck) - myRouter.HandleFunc("/get/character/{user}/{char}", getCharacter) + + // Health check path + myRouter.HandleFunc("/health", healthCheck).Methods("GET") + + // Character routes + myRouter.HandleFunc("/get/character/{user}/{char}", getCharacter).Methods("GET") + myRouter.HandleFunc("/create/character/{user}/{char}", createCharacter).Methods("POST") + + // Skin routes + myRouter.HandleFunc("/get/skin/{skin}", getSkin).Methods("GET") + myRouter.HandleFunc("/create/skin/{skin}", createSkin).Methods("POST") + + // Run webserver log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), myRouter)) }