Skip to content

Updated pythia server #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"go.autocompleteUnimportedPackages": true
}
Binary file added bin/gocode.exe
Binary file not shown.
Binary file added bin/gopkgs.exe
Binary file not shown.
Binary file added bin/goreturns.exe
Binary file not shown.
5 changes: 4 additions & 1 deletion go/pythia.mk
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ GO_OUT_BINARIES := $(addprefix $(OUT_DIR)/,$(GO_INSTALL_BINARIES))

$(call add_target,go,BUILD,Build go code)
all: go
go: $(GO_TARGETS) $(GO_OUT_BINARIES)
go: go_deps $(GO_TARGETS) $(GO_OUT_BINARIES)

go_deps:
go get -u github.com/gorilla/mux

$(GO_TARGETS): $(GO_SOURCES)
$(GO) install $(addsuffix /...,$(GO_PACKAGES))
Expand Down
1 change: 1 addition & 0 deletions go/src/github.com/gorilla/context
Submodule context added at 08b5f4
1 change: 1 addition & 0 deletions go/src/github.com/gorilla/mux
Submodule mux added at e3702b
49 changes: 49 additions & 0 deletions go/src/pythia/frontend/confReader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package frontend

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
)

//Conf struct for the config.json file
type Conf struct {
IP []string
}

var myConf Conf

//GetConf that was or will be loaded from the config.json file
func GetConf() Conf {
//check if not initialized
if cap(myConf.IP) == 0 {
fmt.Println("ip = 0")
myConf = LoadConf()
}
fmt.Println("sending conf")
return myConf
}

//LoadConf to retreive the data from the conf.json file
func LoadConf() Conf {
var conf Conf
//Problem with the congif.json file: it must be in the go/bin/ directory to be loaded
c, err := ioutil.ReadFile("./config.json")
if err != nil {
log.Println("Could not open conf file, default configuration loaded")
return LoadDefaultConf()
}

if err := json.Unmarshal(c, &conf); err != nil {
log.Println("Could not retreive data from conf file default configuration loaded")
return LoadDefaultConf()
}

return conf
}

func LoadDefaultConf() Conf {
conf := Conf{[]string{"127.0.0.1", "::1"}}
return conf
}
91 changes: 91 additions & 0 deletions go/src/pythia/frontend/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package frontend

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"pythia"
)

//Echo the given message in a JSON Message struct format
func Echo(rw http.ResponseWriter, r *http.Request) {
var message map[string]string
body, err := ioutil.ReadAll(r.Body)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
}
if err := json.Unmarshal(body, &message); err != nil {
Error422(rw, err)
return
}
for key := range message {
if key == "text" {
if err := json.NewEncoder(rw).Encode("Reply: " + message["text"]); err != nil {
panic(err)
}
return
}
}
Error422(rw, err)

}

// Task function for the server.
func Task(rw http.ResponseWriter, req *http.Request) {
log.Println("Client connected: ", req.URL)
if req.Method != "POST" {
rw.WriteHeader(http.StatusMethodNotAllowed)
return
}
// Reading the task request
body, err := ioutil.ReadAll(req.Body)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
var taskReq taskRequest
if err := json.Unmarshal([]byte(body), &taskReq); err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
// Connection to the pool and execution of the task
conn := pythia.DialRetry(pythia.QueueAddr)
defer conn.Close()
content, err := ioutil.ReadFile("tasks/" + taskReq.Tid + ".task")
if err != nil {
Error422(rw, err)
return
}
var task pythia.Task
if err := json.Unmarshal([]byte(content), &task); err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
conn.Send(pythia.Message{
Message: pythia.LaunchMsg,
Id: "test",
Task: &task,
Input: taskReq.Response,
})
if msg, ok := <-conn.Receive(); ok {
switch msg.Status {
case "success":
fmt.Fprintf(rw, msg.Output)
}
return
}
rw.WriteHeader(http.StatusInternalServerError)
}

//Error422 response
func Error422(w http.ResponseWriter, err error) {
//Unprocessable Entity if can't convert to struct
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(422)
w.Write([]byte("Error 422: Unprocessable Entity "))
if err := json.NewEncoder(w).Encode(err); err != nil {
panic(err)
}
}
84 changes: 84 additions & 0 deletions go/src/pythia/frontend/routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package frontend

import (
"net"
"net/http"
"strings"

"github.com/gorilla/mux"
)

//Route struct to easily add new roots
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}

//Routes is a list of Route
type Routes []Route

//NewRouter changed mux.Router func to work with the Rout struct
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)

for _, route := range routes {
router.Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}

return router
}

//MiddleWare check the IP of client with the list of IPs in conf.jdon
func MiddleWare(h http.Handler) http.Handler {

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

addr := GetClientIPs(r)
IPConf := GetConf().IP

for _, ipConf := range IPConf {
for _, ipClient := range addr {
if ipConf == ipClient {
h.ServeHTTP(w, r)
return
}
}
}
http.Error(w, "Unauthorized IP address", 401)
return
})
}

//GetClientIPs returns the IPs address of client
func GetClientIPs(r *http.Request) []string {
//If X-FORWARDED-FOR structure is respected (first IP is the client's private IP address)
//and separate with ", "
//Header.Get will have all other IPs but not the last one used (last proxy or client if empty)
var IPs []string
if allIP := r.Header.Get("W-FORWARDED-FOR"); len(allIP) > 0 {
IPs = strings.Split(allIP, ", ")
}
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
IPs = append(IPs, ip)
return IPs
}

var routes = Routes{
Route{
"Echo",
"POST",
"/api/echo",
Echo,
},
Route{
"Task",
"POST",
"/execute",
Task,
},
}
60 changes: 8 additions & 52 deletions go/src/pythia/frontend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
package frontend

import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/signal"
"pythia"
"strconv"
"syscall"
)

Expand Down Expand Up @@ -82,9 +80,14 @@ func (server *Server) Run() {
os.Exit(0)
}()
// Start the web server
http.HandleFunc("/execute", handler)
router := NewRouter()
httpServ := &http.Server{
Addr: ":" + strconv.Itoa(server.Port),
Handler: MiddleWare(router),
}

log.Println("Server listening on", server.Port)
if err := http.ListenAndServe(fmt.Sprint(":", server.Port), nil); err != nil {
if err := httpServ.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
Expand All @@ -93,51 +96,4 @@ func (server *Server) Run() {
func (server *Server) Shutdown() {
}

// Handler function for the server.
func handler(rw http.ResponseWriter, req *http.Request) {
log.Println("Client connected: ", req.URL)
if req.Method != "POST" {
rw.WriteHeader(http.StatusMethodNotAllowed)
return
}
// Reading the task request
body, err := ioutil.ReadAll(req.Body)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
var taskReq taskRequest
if err := json.Unmarshal([]byte(body), &taskReq); err != nil {
rw.WriteHeader(http.StatusBadRequest)
return
}
// Connection to the pool and execution of the task
conn := pythia.DialRetry(pythia.QueueAddr)
defer conn.Close()
content, err := ioutil.ReadFile("tasks/" + taskReq.Tid + ".task")
if err != nil {
rw.WriteHeader(422)
return
}
var task pythia.Task
if err := json.Unmarshal([]byte(content), &task); err != nil {
rw.WriteHeader(http.StatusInternalServerError)
return
}
conn.Send(pythia.Message{
Message: pythia.LaunchMsg,
Id: "test",
Task: &task,
Input: taskReq.Response,
})
if msg, ok := <-conn.Receive(); ok {
switch msg.Status {
case "success":
fmt.Fprintf(rw, msg.Output)
}
return
}
rw.WriteHeader(http.StatusInternalServerError)
}

// vim:set sw=4 ts=4 noet:
1 change: 1 addition & 0 deletions src/github.com/MichaelTJones/walk
Submodule walk added at 4748e2
1 change: 1 addition & 0 deletions src/github.com/nsf/gocode
Submodule gocode added at 9d1e03
1 change: 1 addition & 0 deletions src/github.com/sqs/goreturns
Submodule goreturns added at 83e028
1 change: 1 addition & 0 deletions src/github.com/uudashr/gopkgs
Submodule gopkgs added at 1c62af
1 change: 1 addition & 0 deletions src/golang.org/x/tools
Submodule tools added at 48418e