Skip to content

Commit

Permalink
Add base code
Browse files Browse the repository at this point in the history
  • Loading branch information
marconi1992 committed Apr 28, 2019
0 parents commit a301202
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[*]
indent_size = 2
indent_style = space

[*.go]
indent_size = 4
indent_style = tab
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang:1.9

WORKDIR /go/src/app

COPY main.go main.go

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Nova Cluster
Nova Cluster helps to request views from different hypernova servers using only one endpoint.

## Views File

Nova Cluster needs a configuration file `views.json` in order to map the views and their hypernova servers.

```json
{
"Navbar": {
"server": "http://localhost:3031/batch"
},
"Home": {
"server": "http://localhost:3030/batch"
}
}
```

## Using Hypernova Proxy with Docker

```Dockerfile
FROM marconi1992/nova-cluster:1.0.0

COPY views.json views.json
```
159 changes: 159 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package main

import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"strings"
"sync"

"github.com/gorilla/mux"
"github.com/imdario/mergo"
)

type ViewDefinition struct {
Server string
}

type ViewJob struct {
Name string `json:"name"`
Data interface{} `json:"data"`
}

type ViewJobResult struct {
Name string `json:"name"`
Html string `json:"html"`
Duration float32 `json:"duration"`
Success bool `json:"success"`
Error ViewJobError `json:"error"`
}

type ViewJobError struct {
Name string `json:"name"`
Message string `json:"message"`
}

type BatchResponse struct {
Results map[string]ViewJobResult `json:"results"`
}

func BatchRequest(server string, batch map[string]ViewJob) BatchResponse {
b, encodeErr := json.Marshal(batch)

if encodeErr != nil {
log.Fatal(encodeErr)
}

payload := string(b)

resp, reqErr := http.Post(server, "application/json", strings.NewReader(payload))

if reqErr != nil {
log.Fatal(reqErr)
}

defer resp.Body.Close()

body, bodyErr := ioutil.ReadAll(resp.Body)

if bodyErr != nil {
log.Fatal(bodyErr)
}

var response BatchResponse

json.Unmarshal(body, &response)

return response
}

func GetViewDefintions() map[string]ViewDefinition {
dat, err := ioutil.ReadFile("./views.json")

if err != nil {
log.Fatal(err)
}

var viewDefinitions map[string]ViewDefinition

json.Unmarshal(dat, &viewDefinitions)

return viewDefinitions
}

func BatchHandler(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)

if err != nil {
log.Fatal(err)
}

var viewRequests map[string]ViewJob

json.Unmarshal(b, &viewRequests)

viewDefinitions := GetViewDefintions()

aggregatedResponse := BatchResponse{
Results: make(map[string]ViewJobResult),
}

batches := make(map[string]map[string]ViewJob)

for uuid, job := range viewRequests {
server := viewDefinitions[job.Name].Server

if server == "" {
aggregatedResponse.Results[uuid] = ViewJobResult{
Name: job.Name,
Success: false,
Error: ViewJobError{
Name: "ReferenceError",
Message: "Component\"" + job.Name + "\" not registered in cluster",
},
}
continue
}

if batches[server] == nil {
batch := make(map[string]ViewJob)
batches[server] = batch
}

batches[server][uuid] = job
}

var wg sync.WaitGroup
var batchResponsesMap sync.Map

for server, batch := range batches {
wg.Add(1)

go func(server string, batch map[string]ViewJob) {
response := BatchRequest(server, batch)
batchResponsesMap.Store(server, response)
defer wg.Done()
}(server, batch)
}

wg.Wait()

for server := range batches {
response, _ := batchResponsesMap.Load(server)

batchResponse := response.(BatchResponse)
mergo.Merge(&aggregatedResponse.Results, batchResponse.Results)
}

w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(aggregatedResponse)
}

func main() {

router := mux.NewRouter()
router.HandleFunc("/batch", BatchHandler).Methods("POST")

http.ListenAndServe(":8000", router)
}

0 comments on commit a301202

Please sign in to comment.