mirror of
https://github.com/foomo/contentserver.git
synced 2025-10-16 12:25:44 +00:00
different approch for complex multidimensional structures
This commit is contained in:
parent
8a9c1f321f
commit
c5f97d80c9
32
README.md
32
README.md
@ -1,4 +1,4 @@
|
||||
Content2Go Server
|
||||
Content Server
|
||||
===========
|
||||
|
||||
Serves content tree structures very quickly through a json socket api
|
||||
@ -14,22 +14,19 @@ It's up to you how you use it and which data you want to export to the server. O
|
||||
All you have to do is to provide a tree of content nodes as a JSON encoded RepoNode.
|
||||
|
||||
|
||||
| Attribute | Type | Usage |
|
||||
| ------------- |:-------------:| -----:|
|
||||
| Id | string | unique id to identify the node |
|
||||
| MimeType | string | mime-type of the node, e.g. text/html, image/png, ... |
|
||||
| LinkIds | map[string]map[string]string | (symbolic) link/alias to another node |
|
||||
| Handler | string | define a handler to easily control the output rendering |
|
||||
| Regions | []string | define regions for multi-market websites |
|
||||
| Groups | []string | access control |
|
||||
| States | []string | server states |
|
||||
| URIs | map[string]map[string]string | a map of unique URIs for each region and language to resolve and link to the node |
|
||||
| Names | map[string]map[string]string | a name for this node in every region and language |
|
||||
| Hidden | map[string]map[string]bool | hide in menu specific for region and language |
|
||||
| DestinationIds | map[string]map[string]string | alias or symlink handling |
|
||||
| Data | map[string]interface{} | payload data |
|
||||
| Nodes | map[string]*RepoNode | child nodes |
|
||||
| Index | []string | ??? |
|
||||
| Attribute | Type | Usage |
|
||||
| ------------- |:----------------------:| -----:|
|
||||
| Id | string | unique id to identify the node |
|
||||
| MimeType | string | mime-type of the node, e.g. text/html, image/png, ... |
|
||||
| LinkId | string | (symbolic) link/alias to another node |
|
||||
| Groups | []string | access control |
|
||||
| URI | string | a map of unique URIs for each region and language to resolve and link to the node |
|
||||
| Name | string | a name for this node in every region and language |
|
||||
| Hidden | bool | hide in menu specific for region and language |
|
||||
| DestinationId | string | alias or symlink handling |
|
||||
| Data | map[string]interface{} | payload data |
|
||||
| Nodes | map[string]*RepoNode | child nodes |
|
||||
| Index | []string | contains the order of ou nodes|
|
||||
|
||||
|
||||
### Tips
|
||||
@ -43,4 +40,3 @@ All you have to do is to provide a tree of content nodes as a JSON encoded RepoN
|
||||
## Request Data
|
||||
|
||||
There is a PHP Proxy implementation for foomo in Foomo.ContentServer. Feel free to use it or to implement your own proxy in the language you love. The API should be easily to implement in every other framework and language, too.
|
||||
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/foomo/contentserver/server/log"
|
||||
"github.com/foomo/contentserver/server/repo"
|
||||
"github.com/foomo/contentserver/server/requests"
|
||||
"github.com/foomo/contentserver/server/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func contentHandler(w http.ResponseWriter, r *http.Request) {
|
||||
request := requests.NewContent()
|
||||
utils.PopulateRequest(r, request)
|
||||
utils.JsonResponse(w, contentRepo.GetContent(request))
|
||||
}
|
||||
|
||||
func uriHandler(w http.ResponseWriter, r *http.Request) {
|
||||
parts := strings.Split(r.RequestURI, "/")
|
||||
if len(parts) == 5 {
|
||||
utils.JsonResponse(w, contentRepo.GetURI(parts[2], parts[3], parts[4]))
|
||||
} else {
|
||||
wtfHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func wtfHandler(w http.ResponseWriter, r *http.Request) {
|
||||
msg := "unhandled request: " + r.RequestURI
|
||||
fmt.Fprint(w, msg, "\n")
|
||||
log.Error(msg)
|
||||
}
|
||||
|
||||
func update() interface{} {
|
||||
contentRepo.Update()
|
||||
return contentRepo.Directory
|
||||
}
|
||||
|
||||
func commandHandler(w http.ResponseWriter, r *http.Request) {
|
||||
parts := strings.Split(r.RequestURI, "/")
|
||||
switch true {
|
||||
case true == (len(parts) > 1):
|
||||
switch parts[2] {
|
||||
case "update":
|
||||
utils.JsonResponse(w, update())
|
||||
return
|
||||
default:
|
||||
help := make(map[string]interface{})
|
||||
help["input"] = parts[2]
|
||||
help["commands"] = []string{"update", "help", "content"}
|
||||
utils.JsonResponse(w, help)
|
||||
}
|
||||
default:
|
||||
wtfHandler(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func Run(addr string, serverUrl string) {
|
||||
log.Notice("starting content server")
|
||||
log.Notice(" loading content from " + serverUrl)
|
||||
contentRepo = repo.NewRepo(serverUrl)
|
||||
contentRepo.Update()
|
||||
log.Notice(" loaded " + strconv.Itoa(len(contentRepo.Directory)) + " items")
|
||||
http.HandleFunc("/content", contentHandler)
|
||||
http.HandleFunc("/uri/", uriHandler)
|
||||
http.HandleFunc("/cmd/", commandHandler)
|
||||
http.HandleFunc("/", wtfHandler)
|
||||
log.Notice(" starting service on " + addr)
|
||||
http.ListenAndServe(addr, nil)
|
||||
}
|
||||
@ -6,39 +6,21 @@ import (
|
||||
)
|
||||
|
||||
type RepoNode struct {
|
||||
Id string `json:"id"` // unique identifier - it is your responsibility, that they are unique
|
||||
MimeType string `json:"mimeType"` // well a mime type http://www.ietf.org/rfc/rfc2046.txt
|
||||
LinkIds map[string]map[string]string `json:"linkIds"` // (symbolic) link/alias to another node
|
||||
Handler string `json:"handler"` // that information is for you
|
||||
Regions []string `json:"regions"` // in what regions is this node available, if empty it will be accessible everywhere
|
||||
Groups []string `json:"groups"` // which groups have access to the node, if empty everybody has access to it
|
||||
States []string `json:"states"` // in which states is this node valid, if empty => in all of them
|
||||
URIs map[string]map[string]string `json:"URIs"`
|
||||
Names map[string]map[string]string `json:"names"`
|
||||
Hidden map[string]map[string]bool `json:"hidden"` // hidden in content.nodes, but can still be resolved when being directly addressed
|
||||
DestinationIds map[string]map[string]string `json:"destinationIds"` // if a node does not have any content like a folder the destinationIds can point to nodes that do aka. the first displayable child node
|
||||
Data map[string]interface{} `json:"data"` // what ever you want to stuff into it - the payload you want to attach to a node
|
||||
Nodes map[string]*RepoNode `json:"nodes"` // child nodes
|
||||
Index []string `json:"index"` // defines the order of the child nodes
|
||||
parent *RepoNode // parent node - helps to resolve a path / bread crumb
|
||||
Id string `json:"id"` // unique identifier - it is your responsibility, that they are unique
|
||||
MimeType string `json:"mimeType"` // well a mime type http://www.ietf.org/rfc/rfc2046.txt
|
||||
LinkId string `json:"linkIds"` // (symbolic) link/alias to another node
|
||||
Groups []string `json:"groups"` // which groups have access to the node, if empty everybody has access to it
|
||||
URI string `json:"URI"`
|
||||
Name string `json:"names"`
|
||||
Hidden bool `json:"hidden"` // hidden in content.nodes, but can still be resolved when being directly addressed
|
||||
DestinationId string `json:"destinationId"` // if a node does not have any content like a folder the destinationIds can point to nodes that do aka. the first displayable child node
|
||||
Data map[string]interface{} `json:"data"` // what ever you want to stuff into it - the payload you want to attach to a node
|
||||
Nodes map[string]*RepoNode `json:"nodes"` // child nodes
|
||||
Index []string `json:"index"` // defines the order of the child nodes
|
||||
parent *RepoNode // parent node - helps to resolve a path / bread crumb
|
||||
// published from - to is going to be an array of fromTos
|
||||
}
|
||||
|
||||
func (node *RepoNode) GetLanguageAndRegionForURI(URI string) (resolved bool, region string, language string) {
|
||||
for possibleRegion, URIs := range node.URIs {
|
||||
for possibleLanguage, regionLangURI := range URIs {
|
||||
if regionLangURI == URI {
|
||||
resolved = true
|
||||
region = possibleRegion
|
||||
language = possibleLanguage
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
resolved = false
|
||||
return
|
||||
}
|
||||
|
||||
func (node *RepoNode) WireParents() {
|
||||
for _, childNode := range node.Nodes {
|
||||
childNode.parent = node
|
||||
@ -56,29 +38,7 @@ func (node *RepoNode) InPath(path []*Item) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (node *RepoNode) InState(state string) bool {
|
||||
if len(node.States) == 0 {
|
||||
return true
|
||||
} else {
|
||||
for _, nodeState := range node.States {
|
||||
if state == nodeState {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (node *RepoNode) InRegion(region string) bool {
|
||||
for _, nodeRegion := range node.Regions {
|
||||
if nodeRegion == region {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (node *RepoNode) GetPath(region string, language string) []*Item {
|
||||
func (node *RepoNode) GetPath() []*Item {
|
||||
parentNode := node.parent
|
||||
pathLength := 0
|
||||
for parentNode != nil {
|
||||
@ -89,18 +49,18 @@ func (node *RepoNode) GetPath(region string, language string) []*Item {
|
||||
i := 0
|
||||
path := make([]*Item, pathLength)
|
||||
for parentNode != nil {
|
||||
path[i] = parentNode.ToItem(region, language, []string{})
|
||||
path[i] = parentNode.ToItem([]string{})
|
||||
parentNode = parentNode.parent
|
||||
i++
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (node *RepoNode) ToItem(region string, language string, dataFields []string) *Item {
|
||||
func (node *RepoNode) ToItem(dataFields []string) *Item {
|
||||
item := NewItem()
|
||||
item.Id = node.Id
|
||||
item.Name = node.GetName(region, language)
|
||||
item.URI = node.URIs[region][language] //uri //repo.GetURI(region, language, node.Id)
|
||||
item.Name = node.Name
|
||||
item.URI = node.URI
|
||||
for _, dataField := range dataFields {
|
||||
if data, ok := node.Data[dataField]; ok {
|
||||
item.Data[dataField] = data
|
||||
@ -118,21 +78,6 @@ func (node *RepoNode) AddNode(name string, childNode *RepoNode) *RepoNode {
|
||||
return node
|
||||
}
|
||||
|
||||
func (node *RepoNode) IsHidden(region string, language string) bool {
|
||||
if regionMap, ok := node.Hidden[region]; ok {
|
||||
if languageHidden, ok := regionMap[language]; ok {
|
||||
return languageHidden
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (node *RepoNode) GetName(region string, language string) string {
|
||||
return node.Names[region][language]
|
||||
}
|
||||
|
||||
func (node *RepoNode) IsOneOfTheseMimeTypes(mimeTypes []string) bool {
|
||||
if len(mimeTypes) == 0 {
|
||||
return true
|
||||
@ -164,10 +109,7 @@ func (node *RepoNode) CanBeAccessedByGroups(groups []string) bool {
|
||||
|
||||
func (node *RepoNode) PrintNode(id string, level int) {
|
||||
prefix := strings.Repeat(INDENT, level)
|
||||
fmt.Printf("%s %s:\n", prefix, id)
|
||||
for lang, name := range node.Names {
|
||||
fmt.Printf("%s %s: %s\n", prefix+INDENT, lang, name)
|
||||
}
|
||||
fmt.Printf("%s %s %s:\n", prefix, id, node.Name)
|
||||
for key, childNode := range node.Nodes {
|
||||
childNode.PrintNode(key, level+1)
|
||||
}
|
||||
|
||||
@ -7,16 +7,15 @@ const (
|
||||
)
|
||||
|
||||
type SiteContent struct {
|
||||
Status int `json:"status"`
|
||||
URI string `json:"URI"`
|
||||
Region string `json:"region"`
|
||||
Language string `json:"language"`
|
||||
Handler string `json:"handler"`
|
||||
Item *Item `json:"item"`
|
||||
Data interface{} `json:"data"`
|
||||
Path []*Item `json:"path"`
|
||||
URIs map[string]string `json:"URIs"`
|
||||
Nodes map[string]*Node `json:"nodes"`
|
||||
Status int `json:"status"`
|
||||
URI string `json:"URI"`
|
||||
Dimension string `json:"dimension"`
|
||||
MimeType string `json:"mimeType"`
|
||||
Item *Item `json:"item"`
|
||||
Data interface{} `json:"data"`
|
||||
Path []*Item `json:"path"`
|
||||
URIs map[string]string `json:"URIs"`
|
||||
Nodes map[string]*Node `json:"nodes"`
|
||||
}
|
||||
|
||||
func NewSiteContent() *SiteContent {
|
||||
|
||||
@ -12,38 +12,49 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Dimension struct {
|
||||
Directory map[string]*content.RepoNode
|
||||
URIDirectory map[string]*content.RepoNode
|
||||
Node *content.RepoNode
|
||||
}
|
||||
|
||||
type RepoDimension struct {
|
||||
Dimension string
|
||||
Node *content.RepoNode
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
server string
|
||||
Regions []string
|
||||
Languages []string
|
||||
Directory map[string]*content.RepoNode
|
||||
URIDirectory map[string]*content.RepoNode
|
||||
Node *content.RepoNode
|
||||
updateChannel chan *content.RepoNode
|
||||
Directory map[string]*Dimension
|
||||
updateChannel chan *RepoDimension
|
||||
updateDoneChannel chan error
|
||||
}
|
||||
|
||||
func NewRepo(server string) *Repo {
|
||||
log.Notice("creating new repo for " + server)
|
||||
repo := new(Repo)
|
||||
repo.Directory = make(map[string]*Dimension)
|
||||
repo.server = server
|
||||
repo.updateChannel = make(chan *content.RepoNode)
|
||||
repo.updateChannel = make(chan *RepoDimension)
|
||||
repo.updateDoneChannel = make(chan error)
|
||||
go func() {
|
||||
select {
|
||||
case newNode := <-repo.updateChannel:
|
||||
repo.updateDoneChannel <- repo.load(newNode)
|
||||
case newDimension := <-repo.updateChannel:
|
||||
repo.updateDoneChannel <- repo.load(newDimension.Dimension, newDimension.Node)
|
||||
}
|
||||
}()
|
||||
return repo
|
||||
}
|
||||
|
||||
func (repo *Repo) Load(newNode *content.RepoNode) error {
|
||||
repo.updateChannel <- newNode
|
||||
func (repo *Repo) Load(dimension string, node *content.RepoNode) error {
|
||||
repo.updateChannel <- &RepoDimension{
|
||||
Dimension: dimension,
|
||||
Node: node,
|
||||
}
|
||||
return <-repo.updateDoneChannel
|
||||
}
|
||||
|
||||
func (repo *Repo) load(newNode *content.RepoNode) error {
|
||||
func (repo *Repo) load(dimension string, newNode *content.RepoNode) error {
|
||||
newNode.WireParents()
|
||||
newDirectory := make(map[string]*content.RepoNode)
|
||||
newURIDirectory := make(map[string]*content.RepoNode)
|
||||
@ -56,104 +67,81 @@ func (repo *Repo) load(newNode *content.RepoNode) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repo.Node = newNode
|
||||
repo.Directory = newDirectory
|
||||
repo.URIDirectory = newURIDirectory
|
||||
repo.Directory[dimension] = &Dimension{
|
||||
Node: newNode,
|
||||
Directory: newDirectory,
|
||||
URIDirectory: newURIDirectory,
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (repo *Repo) ResolveContent(state string, URI string) (resolved bool, resolvedURI string, region string, language string, repoNode *content.RepoNode) {
|
||||
func (repo *Repo) ResolveContent(dimensions []string, URI string) (resolved bool, resolvedURI string, resolvedDimension string, repoNode *content.RepoNode) {
|
||||
parts := strings.Split(URI, content.PATH_SEPARATOR)
|
||||
log.Debug("repo.ResolveContent: " + URI)
|
||||
for i := len(parts); i > -1; i-- {
|
||||
testURI := strings.Join(parts[0:i], content.PATH_SEPARATOR)
|
||||
testURIKey := uriKeyForState(state, testURI)
|
||||
log.Debug(" testing" + testURIKey)
|
||||
if repoNode, ok := repo.URIDirectory[testURIKey]; ok {
|
||||
resolved = true
|
||||
_, region, language := repoNode.GetLanguageAndRegionForURI(testURI)
|
||||
log.Debug(" => " + testURIKey)
|
||||
log.Debug(" destination " + fmt.Sprint(repoNode.DestinationIds))
|
||||
// check this one
|
||||
// repoNode = repo.Directory[repoNode.DestinationIds]
|
||||
|
||||
if languageDestinations, regionOk := repoNode.DestinationIds[region]; regionOk {
|
||||
// this check should happen, when updating the repo
|
||||
log.Debug(" there is a destionation map for this one " + fmt.Sprint(languageDestinations))
|
||||
if languageDestination, destinationOk := languageDestinations[language]; destinationOk {
|
||||
if destinationNode, destinationNodeOk := repo.Directory[languageDestination]; destinationNodeOk {
|
||||
repoNode = destinationNode
|
||||
} else {
|
||||
log.Debug(" could not resolve this destinationId : " + languageDestination)
|
||||
for _, dimension := range dimensions {
|
||||
if d, ok := repo.Directory[dimension]; ok {
|
||||
for i := len(parts); i > -1; i-- {
|
||||
testURI := strings.Join(parts[0:i], content.PATH_SEPARATOR)
|
||||
log.Debug(" testing" + testURI)
|
||||
if repoNode, ok := d.URIDirectory[testURI]; ok {
|
||||
resolved = true
|
||||
log.Debug(" => " + testURI)
|
||||
log.Debug(" destination " + fmt.Sprint(repoNode.DestinationId))
|
||||
if len(repoNode.DestinationId) > 0 {
|
||||
if destionationNode, destinationNodeOk := d.Directory[repoNode.DestinationId]; destinationNodeOk {
|
||||
repoNode = destionationNode
|
||||
}
|
||||
}
|
||||
return true, testURI, dimension, repoNode
|
||||
} else {
|
||||
log.Debug(" => !" + testURI)
|
||||
resolved = false
|
||||
}
|
||||
}
|
||||
return true, testURI, region, language, repoNode
|
||||
} else {
|
||||
log.Debug(" => !" + testURI)
|
||||
resolved = false
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (repo *Repo) GetItemMap(id string, dataFields []string) map[string]map[string]*content.Item {
|
||||
itemMap := make(map[string]map[string]*content.Item)
|
||||
if repoNode, ok := repo.Directory[id]; ok {
|
||||
for region, languageURIs := range repoNode.URIs {
|
||||
itemMap[region] = make(map[string]*content.Item)
|
||||
for language, URI := range languageURIs {
|
||||
log.Debug(fmt.Sprintf("region :%s language :%s URI: %s", region, language, URI))
|
||||
itemMap[region][language] = repoNode.ToItem(region, language, dataFields)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warning("GetItemMapForAllRegionsAndLanguages invalid id " + id)
|
||||
}
|
||||
return itemMap
|
||||
}
|
||||
|
||||
func (repo *Repo) GetURIs(region string, language string, ids []string) map[string]string {
|
||||
func (repo *Repo) GetURIs(dimension string, ids []string) map[string]string {
|
||||
uris := make(map[string]string)
|
||||
for _, id := range ids {
|
||||
uris[id] = repo.GetURI(region, language, id)
|
||||
uris[id] = repo.GetURI(dimension, id)
|
||||
}
|
||||
return uris
|
||||
}
|
||||
|
||||
func (repo *Repo) GetURIForNode(region string, language string, repoNode *content.RepoNode) string {
|
||||
func (repo *Repo) GetURIForNode(dimension string, repoNode *content.RepoNode) string {
|
||||
|
||||
if len(repoNode.LinkIds) == 0 {
|
||||
languageURIs, regionExists := repoNode.URIs[region]
|
||||
if regionExists {
|
||||
languageURI, languageURIExists := languageURIs[language]
|
||||
if languageURIExists {
|
||||
return languageURI
|
||||
}
|
||||
}
|
||||
return ""
|
||||
if len(repoNode.LinkId) == 0 {
|
||||
return repoNode.URI
|
||||
} else {
|
||||
return repo.GetURI(region, language, repoNode.LinkIds[region][language])
|
||||
linkedNode, ok := repo.Directory[dimension].Directory[repoNode.LinkId]
|
||||
if ok {
|
||||
return repo.GetURIForNode(dimension, linkedNode)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (repo *Repo) GetURI(region string, language string, id string) string {
|
||||
repoNode, ok := repo.Directory[id]
|
||||
func (repo *Repo) GetURI(dimension string, id string) string {
|
||||
repoNode, ok := repo.Directory[dimension].Directory[id]
|
||||
if ok {
|
||||
return repo.GetURIForNode(region, language, repoNode)
|
||||
return repo.GetURIForNode(dimension, repoNode)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (repo *Repo) GetNode(repoNode *content.RepoNode, expanded bool, mimeTypes []string, path []*content.Item, level int, state string, groups []string, region string, language string, dataFields []string) *content.Node {
|
||||
func (repo *Repo) GetNode(repoNode *content.RepoNode, expanded bool, mimeTypes []string, path []*content.Item, level int, groups []string, dataFields []string) *content.Node {
|
||||
node := content.NewNode()
|
||||
node.Item = repoNode.ToItem(region, language, dataFields)
|
||||
node.Item = repoNode.ToItem(dataFields)
|
||||
log.Debug("repo.GetNode: " + repoNode.Id)
|
||||
for _, childId := range repoNode.Index {
|
||||
childNode := repoNode.Nodes[childId]
|
||||
if (level == 0 || expanded || !expanded && childNode.InPath(path)) && childNode.InState(state) && !childNode.IsHidden(region, language) && childNode.CanBeAccessedByGroups(groups) && childNode.IsOneOfTheseMimeTypes(mimeTypes) && childNode.InRegion(region) {
|
||||
node.Nodes[childId] = repo.GetNode(childNode, expanded, mimeTypes, path, level+1, state, groups, region, language, dataFields)
|
||||
if (level == 0 || expanded || !expanded && childNode.InPath(path)) && !childNode.Hidden && childNode.CanBeAccessedByGroups(groups) && childNode.IsOneOfTheseMimeTypes(mimeTypes) {
|
||||
node.Nodes[childId] = repo.GetNode(childNode, expanded, mimeTypes, path, level+1, groups, dataFields)
|
||||
node.Index = append(node.Index, childId)
|
||||
}
|
||||
}
|
||||
@ -165,8 +153,8 @@ func (repo *Repo) GetNodes(r *requests.Nodes) map[string]*content.Node {
|
||||
path := make([]*content.Item, 0)
|
||||
for nodeName, nodeRequest := range r.Nodes {
|
||||
log.Debug(" adding node " + nodeName + " " + nodeRequest.Id)
|
||||
if treeNode, ok := repo.Directory[nodeRequest.Id]; ok {
|
||||
nodes[nodeName] = repo.GetNode(treeNode, nodeRequest.Expand, nodeRequest.MimeTypes, path, 0, r.Env.State, r.Env.Groups, r.Env.Defaults.Region, r.Env.Defaults.Language, nodeRequest.DataFields)
|
||||
if treeNode, ok := repo.Directory[nodeRequest.Dimension].Directory[nodeRequest.Id]; ok {
|
||||
nodes[nodeName] = repo.GetNode(treeNode, nodeRequest.Expand, nodeRequest.MimeTypes, path, 0, r.Env.Groups, nodeRequest.DataFields)
|
||||
} else {
|
||||
log.Warning("you are requesting an invalid tree node for " + nodeName + " : " + nodeRequest.Id)
|
||||
}
|
||||
@ -177,28 +165,26 @@ func (repo *Repo) GetNodes(r *requests.Nodes) map[string]*content.Node {
|
||||
func (repo *Repo) GetContent(r *requests.Content) *content.SiteContent {
|
||||
log.Debug("repo.GetContent: " + r.URI)
|
||||
c := content.NewSiteContent()
|
||||
resolved, resolvedURI, region, language, node := repo.ResolveContent(r.Env.State, r.URI)
|
||||
resolved, resolvedURI, resolvedDimension, node := repo.ResolveContent(r.Env.Dimensions, r.URI)
|
||||
if resolved {
|
||||
log.Notice("200 for " + r.URI)
|
||||
// forbidden ?!
|
||||
c.Region = region
|
||||
c.Language = language
|
||||
c.Status = content.STATUS_OK
|
||||
c.Handler = node.Handler
|
||||
c.MimeType = node.MimeType
|
||||
c.Dimension = resolvedDimension
|
||||
c.URI = resolvedURI
|
||||
c.Item = node.ToItem(region, language, []string{})
|
||||
c.Path = node.GetPath(region, language)
|
||||
c.Item = node.ToItem([]string{})
|
||||
c.Path = node.GetPath()
|
||||
c.Data = node.Data
|
||||
} else {
|
||||
log.Notice("404 for " + r.URI)
|
||||
c.Status = content.STATUS_NOT_FOUND
|
||||
region = r.Env.Defaults.Region
|
||||
language = r.Env.Defaults.Language
|
||||
c.Dimension = r.Env.Dimensions[0]
|
||||
}
|
||||
for treeName, treeRequest := range r.Nodes {
|
||||
log.Debug(" adding tree " + treeName + " " + treeRequest.Id)
|
||||
if treeNode, ok := repo.Directory[treeRequest.Id]; ok {
|
||||
c.Nodes[treeName] = repo.GetNode(treeNode, treeRequest.Expand, treeRequest.MimeTypes, c.Path, 0, r.Env.State, r.Env.Groups, region, language, treeRequest.DataFields)
|
||||
if treeNode, ok := repo.Directory[resolvedDimension].Directory[treeRequest.Id]; ok {
|
||||
c.Nodes[treeName] = repo.GetNode(treeNode, treeRequest.Expand, treeRequest.MimeTypes, c.Path, 0, r.Env.Groups, treeRequest.DataFields)
|
||||
} else {
|
||||
log.Warning("you are requesting an invalid tree node for " + treeName + " : " + treeRequest.Id)
|
||||
}
|
||||
@ -206,10 +192,11 @@ func (repo *Repo) GetContent(r *requests.Content) *content.SiteContent {
|
||||
return c
|
||||
}
|
||||
|
||||
/*
|
||||
func (repo *Repo) GetRepo() *content.RepoNode {
|
||||
return repo.Node
|
||||
}
|
||||
|
||||
*/
|
||||
func uriKeyForState(state string, uri string) string {
|
||||
return state + "-" + uri
|
||||
}
|
||||
@ -222,30 +209,10 @@ func builDirectory(dirNode *content.RepoNode, directory map[string]*content.Repo
|
||||
}
|
||||
directory[dirNode.Id] = dirNode
|
||||
//todo handle duplicate uris
|
||||
for _, languageURIs := range dirNode.URIs {
|
||||
for _, uri := range languageURIs {
|
||||
log.Debug(" uri: " + uri + " => Id: " + dirNode.Id)
|
||||
if len(dirNode.States) == 0 {
|
||||
key := uriKeyForState("", uri)
|
||||
existingNode, ok = uRIDirectory[key]
|
||||
if ok {
|
||||
return errors.New("duplicate node with uri: " + uri)
|
||||
}
|
||||
uRIDirectory[key] = dirNode
|
||||
} else {
|
||||
|
||||
for _, state := range dirNode.States {
|
||||
key := uriKeyForState(state, uri)
|
||||
existingNode, ok = uRIDirectory[key]
|
||||
if ok {
|
||||
return errors.New("dupicate node with uri: " + uri + " for state " + state)
|
||||
}
|
||||
uRIDirectory[key] = dirNode
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if _, thereIsAnExistingUriNode := uRIDirectory[dirNode.URI]; thereIsAnExistingUriNode {
|
||||
return errors.New("duplicate node with uri: " + dirNode.URI)
|
||||
}
|
||||
uRIDirectory[dirNode.URI] = dirNode
|
||||
for _, childNode := range dirNode.Nodes {
|
||||
err := builDirectory(childNode, directory, uRIDirectory)
|
||||
if err != nil {
|
||||
@ -256,15 +223,12 @@ func builDirectory(dirNode *content.RepoNode, directory map[string]*content.Repo
|
||||
}
|
||||
|
||||
func wireAliases(directory map[string]*content.RepoNode) error {
|
||||
// validation ?!
|
||||
for _, repoNode := range directory {
|
||||
if len(repoNode.LinkIds) > 0 {
|
||||
for region, languages := range repoNode.LinkIds {
|
||||
for language, linkId := range languages {
|
||||
if destinationNode, ok := directory[linkId]; ok {
|
||||
repoNode.URIs[region][language] = destinationNode.URIs[region][language]
|
||||
}
|
||||
}
|
||||
if len(repoNode.LinkId) > 0 {
|
||||
if destinationNode, ok := directory[repoNode.LinkId]; ok {
|
||||
repoNode.URI = destinationNode.URI
|
||||
} else {
|
||||
return errors.New("that link id point nowhere " + repoNode.LinkId + " from " + repoNode.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,16 +237,18 @@ func wireAliases(directory map[string]*content.RepoNode) error {
|
||||
|
||||
func (repo *Repo) Update() *responses.Update {
|
||||
updateResponse := responses.NewUpdate()
|
||||
newNode := content.NewRepoNode()
|
||||
newNodes := make(map[string]*content.RepoNode) //content.NewRepoNode()
|
||||
startTimeRepo := time.Now()
|
||||
ok, err := utils.Get(repo.server, newNode)
|
||||
ok, err := utils.Get(repo.server, newNodes)
|
||||
updateResponse.Stats.RepoRuntime = time.Now().Sub(startTimeRepo).Seconds()
|
||||
startTimeOwn := time.Now()
|
||||
updateResponse.Success = ok
|
||||
if ok {
|
||||
repo.Load(newNode)
|
||||
updateResponse.Stats.NumberOfNodes = len(repo.Directory)
|
||||
updateResponse.Stats.NumberOfURIs = len(repo.URIDirectory)
|
||||
for dimension, newNode := range newNodes {
|
||||
repo.Load(dimension, newNode)
|
||||
updateResponse.Stats.NumberOfNodes = len(repo.Directory[dimension].Directory)
|
||||
updateResponse.Stats.NumberOfURIs = len(repo.Directory[dimension].URIDirectory)
|
||||
}
|
||||
} else {
|
||||
log.Error(fmt.Sprintf("update error: %", err))
|
||||
updateResponse.ErrorMessage = fmt.Sprintf("%", err)
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package requests
|
||||
|
||||
type Content struct {
|
||||
Env *Env `json:"env"`
|
||||
URI string
|
||||
Env *Env `json:"env"`
|
||||
URI string `json:"URI"`
|
||||
Nodes map[string]*Node `json:"nodes"`
|
||||
}
|
||||
|
||||
|
||||
@ -1,19 +1,14 @@
|
||||
package requests
|
||||
|
||||
type Defaults struct {
|
||||
Region string `json:"region"`
|
||||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
type Env struct {
|
||||
Defaults *Defaults `json:"defaults"`
|
||||
Groups []string `json:"groups"`
|
||||
State string
|
||||
Data interface{} `json:"data"`
|
||||
Dimensions []string `json:"dimensions"`
|
||||
Groups []string `json:"groups"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Id string `json:"id"`
|
||||
Dimension string `json:"id"`
|
||||
MimeTypes []string `json:"mimeTypes"`
|
||||
Expand bool `json:"expand"`
|
||||
DataFields []string `json:"dataFields"`
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package requests
|
||||
|
||||
type URIs struct {
|
||||
Ids []string `json:"ids"`
|
||||
Region string `json:"region"`
|
||||
Language string `json:"language"`
|
||||
Ids []string `json:"ids"`
|
||||
Dimension string `json:"dimension"`
|
||||
}
|
||||
|
||||
func NewURIs() *URIs {
|
||||
|
||||
@ -32,7 +32,7 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
||||
getURIRequest := requests.NewURIs()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &getURIRequest)
|
||||
log.Debug(" getURIRequest: " + fmt.Sprint(getURIRequest))
|
||||
uris := contentRepo.GetURIs(getURIRequest.Region, getURIRequest.Language, getURIRequest.Ids)
|
||||
uris := contentRepo.GetURIs(getURIRequest.Dimension, getURIRequest.Ids)
|
||||
log.Debug(" resolved: " + fmt.Sprint(uris))
|
||||
reply = uris
|
||||
break
|
||||
@ -43,13 +43,15 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
||||
content := contentRepo.GetContent(contentRequest)
|
||||
reply = content
|
||||
break
|
||||
case "getItemMap":
|
||||
itemMapRequest := requests.NewItemMap()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &itemMapRequest)
|
||||
log.Debug(" itemMapRequest: " + fmt.Sprint(itemMapRequest))
|
||||
itemMap := contentRepo.GetItemMap(itemMapRequest.Id, itemMapRequest.DataFields)
|
||||
reply = itemMap
|
||||
break
|
||||
/*
|
||||
case "getItemMap":
|
||||
itemMapRequest := requests.NewItemMap()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &itemMapRequest)
|
||||
log.Debug(" itemMapRequest: " + fmt.Sprint(itemMapRequest))
|
||||
itemMap := contentRepo.GetItemMap(itemMapRequest.Id, itemMapRequest.DataFields)
|
||||
reply = itemMap
|
||||
break
|
||||
*/
|
||||
case "getNodes":
|
||||
nodesRequest := requests.NewNodes()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &nodesRequest)
|
||||
@ -64,13 +66,15 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
||||
updateResponse := contentRepo.Update()
|
||||
reply = updateResponse
|
||||
break
|
||||
case "getRepo":
|
||||
repoRequest := requests.NewRepo()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &repoRequest)
|
||||
log.Debug(" getRepoRequest: " + fmt.Sprint(repoRequest))
|
||||
repoResponse := contentRepo.GetRepo()
|
||||
reply = repoResponse
|
||||
break
|
||||
/*
|
||||
case "getRepo":
|
||||
repoRequest := requests.NewRepo()
|
||||
jsonErr = json.Unmarshal(jsonBuffer, &repoRequest)
|
||||
log.Debug(" getRepoRequest: " + fmt.Sprint(repoRequest))
|
||||
repoResponse := contentRepo.GetRepo()
|
||||
reply = repoResponse
|
||||
break
|
||||
*/
|
||||
default:
|
||||
err = errors.New(log.Error(" can not handle this one " + handler))
|
||||
errorResponse := responses.NewError(1, "unkown handler")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user