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
|
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.
|
All you have to do is to provide a tree of content nodes as a JSON encoded RepoNode.
|
||||||
|
|
||||||
|
|
||||||
| Attribute | Type | Usage |
|
| Attribute | Type | Usage |
|
||||||
| ------------- |:-------------:| -----:|
|
| ------------- |:----------------------:| -----:|
|
||||||
| Id | string | unique id to identify the node |
|
| Id | string | unique id to identify the node |
|
||||||
| MimeType | string | mime-type of the node, e.g. text/html, image/png, ... |
|
| 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 |
|
| LinkId | string | (symbolic) link/alias to another node |
|
||||||
| Handler | string | define a handler to easily control the output rendering |
|
| Groups | []string | access control |
|
||||||
| Regions | []string | define regions for multi-market websites |
|
| URI | string | a map of unique URIs for each region and language to resolve and link to the node |
|
||||||
| Groups | []string | access control |
|
| Name | string | a name for this node in every region and language |
|
||||||
| States | []string | server states |
|
| Hidden | bool | hide in menu specific for region and language |
|
||||||
| URIs | map[string]map[string]string | a map of unique URIs for each region and language to resolve and link to the node |
|
| DestinationId | string | alias or symlink handling |
|
||||||
| Names | map[string]map[string]string | a name for this node in every region and language |
|
| Data | map[string]interface{} | payload data |
|
||||||
| Hidden | map[string]map[string]bool | hide in menu specific for region and language |
|
| Nodes | map[string]*RepoNode | child nodes |
|
||||||
| DestinationIds | map[string]map[string]string | alias or symlink handling |
|
| Index | []string | contains the order of ou nodes|
|
||||||
| Data | map[string]interface{} | payload data |
|
|
||||||
| Nodes | map[string]*RepoNode | child nodes |
|
|
||||||
| Index | []string | ??? |
|
|
||||||
|
|
||||||
|
|
||||||
### Tips
|
### 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
|
## 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.
|
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 {
|
type RepoNode struct {
|
||||||
Id string `json:"id"` // unique identifier - it is your responsibility, that they are unique
|
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
|
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
|
LinkId string `json:"linkIds"` // (symbolic) link/alias to another node
|
||||||
Handler string `json:"handler"` // that information is for you
|
Groups []string `json:"groups"` // which groups have access to the node, if empty everybody has access to it
|
||||||
Regions []string `json:"regions"` // in what regions is this node available, if empty it will be accessible everywhere
|
URI string `json:"URI"`
|
||||||
Groups []string `json:"groups"` // which groups have access to the node, if empty everybody has access to it
|
Name string `json:"names"`
|
||||||
States []string `json:"states"` // in which states is this node valid, if empty => in all of them
|
Hidden bool `json:"hidden"` // hidden in content.nodes, but can still be resolved when being directly addressed
|
||||||
URIs map[string]map[string]string `json:"URIs"`
|
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
|
||||||
Names map[string]map[string]string `json:"names"`
|
Data map[string]interface{} `json:"data"` // what ever you want to stuff into it - the payload you want to attach to a node
|
||||||
Hidden map[string]map[string]bool `json:"hidden"` // hidden in content.nodes, but can still be resolved when being directly addressed
|
Nodes map[string]*RepoNode `json:"nodes"` // child nodes
|
||||||
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
|
Index []string `json:"index"` // defines the order of the child nodes
|
||||||
Data map[string]interface{} `json:"data"` // what ever you want to stuff into it - the payload you want to attach to a node
|
parent *RepoNode // parent node - helps to resolve a path / bread crumb
|
||||||
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
|
// 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() {
|
func (node *RepoNode) WireParents() {
|
||||||
for _, childNode := range node.Nodes {
|
for _, childNode := range node.Nodes {
|
||||||
childNode.parent = node
|
childNode.parent = node
|
||||||
@ -56,29 +38,7 @@ func (node *RepoNode) InPath(path []*Item) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *RepoNode) InState(state string) bool {
|
func (node *RepoNode) GetPath() []*Item {
|
||||||
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 {
|
|
||||||
parentNode := node.parent
|
parentNode := node.parent
|
||||||
pathLength := 0
|
pathLength := 0
|
||||||
for parentNode != nil {
|
for parentNode != nil {
|
||||||
@ -89,18 +49,18 @@ func (node *RepoNode) GetPath(region string, language string) []*Item {
|
|||||||
i := 0
|
i := 0
|
||||||
path := make([]*Item, pathLength)
|
path := make([]*Item, pathLength)
|
||||||
for parentNode != nil {
|
for parentNode != nil {
|
||||||
path[i] = parentNode.ToItem(region, language, []string{})
|
path[i] = parentNode.ToItem([]string{})
|
||||||
parentNode = parentNode.parent
|
parentNode = parentNode.parent
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *RepoNode) ToItem(region string, language string, dataFields []string) *Item {
|
func (node *RepoNode) ToItem(dataFields []string) *Item {
|
||||||
item := NewItem()
|
item := NewItem()
|
||||||
item.Id = node.Id
|
item.Id = node.Id
|
||||||
item.Name = node.GetName(region, language)
|
item.Name = node.Name
|
||||||
item.URI = node.URIs[region][language] //uri //repo.GetURI(region, language, node.Id)
|
item.URI = node.URI
|
||||||
for _, dataField := range dataFields {
|
for _, dataField := range dataFields {
|
||||||
if data, ok := node.Data[dataField]; ok {
|
if data, ok := node.Data[dataField]; ok {
|
||||||
item.Data[dataField] = data
|
item.Data[dataField] = data
|
||||||
@ -118,21 +78,6 @@ func (node *RepoNode) AddNode(name string, childNode *RepoNode) *RepoNode {
|
|||||||
return node
|
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 {
|
func (node *RepoNode) IsOneOfTheseMimeTypes(mimeTypes []string) bool {
|
||||||
if len(mimeTypes) == 0 {
|
if len(mimeTypes) == 0 {
|
||||||
return true
|
return true
|
||||||
@ -164,10 +109,7 @@ func (node *RepoNode) CanBeAccessedByGroups(groups []string) bool {
|
|||||||
|
|
||||||
func (node *RepoNode) PrintNode(id string, level int) {
|
func (node *RepoNode) PrintNode(id string, level int) {
|
||||||
prefix := strings.Repeat(INDENT, level)
|
prefix := strings.Repeat(INDENT, level)
|
||||||
fmt.Printf("%s %s:\n", prefix, id)
|
fmt.Printf("%s %s %s:\n", prefix, id, node.Name)
|
||||||
for lang, name := range node.Names {
|
|
||||||
fmt.Printf("%s %s: %s\n", prefix+INDENT, lang, name)
|
|
||||||
}
|
|
||||||
for key, childNode := range node.Nodes {
|
for key, childNode := range node.Nodes {
|
||||||
childNode.PrintNode(key, level+1)
|
childNode.PrintNode(key, level+1)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,16 +7,15 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SiteContent struct {
|
type SiteContent struct {
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
URI string `json:"URI"`
|
URI string `json:"URI"`
|
||||||
Region string `json:"region"`
|
Dimension string `json:"dimension"`
|
||||||
Language string `json:"language"`
|
MimeType string `json:"mimeType"`
|
||||||
Handler string `json:"handler"`
|
Item *Item `json:"item"`
|
||||||
Item *Item `json:"item"`
|
Data interface{} `json:"data"`
|
||||||
Data interface{} `json:"data"`
|
Path []*Item `json:"path"`
|
||||||
Path []*Item `json:"path"`
|
URIs map[string]string `json:"URIs"`
|
||||||
URIs map[string]string `json:"URIs"`
|
Nodes map[string]*Node `json:"nodes"`
|
||||||
Nodes map[string]*Node `json:"nodes"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSiteContent() *SiteContent {
|
func NewSiteContent() *SiteContent {
|
||||||
|
|||||||
@ -12,38 +12,49 @@ import (
|
|||||||
"time"
|
"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 {
|
type Repo struct {
|
||||||
server string
|
server string
|
||||||
Regions []string
|
Directory map[string]*Dimension
|
||||||
Languages []string
|
updateChannel chan *RepoDimension
|
||||||
Directory map[string]*content.RepoNode
|
|
||||||
URIDirectory map[string]*content.RepoNode
|
|
||||||
Node *content.RepoNode
|
|
||||||
updateChannel chan *content.RepoNode
|
|
||||||
updateDoneChannel chan error
|
updateDoneChannel chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepo(server string) *Repo {
|
func NewRepo(server string) *Repo {
|
||||||
log.Notice("creating new repo for " + server)
|
log.Notice("creating new repo for " + server)
|
||||||
repo := new(Repo)
|
repo := new(Repo)
|
||||||
|
repo.Directory = make(map[string]*Dimension)
|
||||||
repo.server = server
|
repo.server = server
|
||||||
repo.updateChannel = make(chan *content.RepoNode)
|
repo.updateChannel = make(chan *RepoDimension)
|
||||||
repo.updateDoneChannel = make(chan error)
|
repo.updateDoneChannel = make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
case newNode := <-repo.updateChannel:
|
case newDimension := <-repo.updateChannel:
|
||||||
repo.updateDoneChannel <- repo.load(newNode)
|
repo.updateDoneChannel <- repo.load(newDimension.Dimension, newDimension.Node)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return repo
|
return repo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) Load(newNode *content.RepoNode) error {
|
func (repo *Repo) Load(dimension string, node *content.RepoNode) error {
|
||||||
repo.updateChannel <- newNode
|
repo.updateChannel <- &RepoDimension{
|
||||||
|
Dimension: dimension,
|
||||||
|
Node: node,
|
||||||
|
}
|
||||||
return <-repo.updateDoneChannel
|
return <-repo.updateDoneChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) load(newNode *content.RepoNode) error {
|
func (repo *Repo) load(dimension string, newNode *content.RepoNode) error {
|
||||||
newNode.WireParents()
|
newNode.WireParents()
|
||||||
newDirectory := make(map[string]*content.RepoNode)
|
newDirectory := make(map[string]*content.RepoNode)
|
||||||
newURIDirectory := 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repo.Node = newNode
|
repo.Directory[dimension] = &Dimension{
|
||||||
repo.Directory = newDirectory
|
Node: newNode,
|
||||||
repo.URIDirectory = newURIDirectory
|
Directory: newDirectory,
|
||||||
|
URIDirectory: newURIDirectory,
|
||||||
|
}
|
||||||
return nil
|
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)
|
parts := strings.Split(URI, content.PATH_SEPARATOR)
|
||||||
log.Debug("repo.ResolveContent: " + URI)
|
log.Debug("repo.ResolveContent: " + URI)
|
||||||
for i := len(parts); i > -1; i-- {
|
for _, dimension := range dimensions {
|
||||||
testURI := strings.Join(parts[0:i], content.PATH_SEPARATOR)
|
if d, ok := repo.Directory[dimension]; ok {
|
||||||
testURIKey := uriKeyForState(state, testURI)
|
for i := len(parts); i > -1; i-- {
|
||||||
log.Debug(" testing" + testURIKey)
|
testURI := strings.Join(parts[0:i], content.PATH_SEPARATOR)
|
||||||
if repoNode, ok := repo.URIDirectory[testURIKey]; ok {
|
log.Debug(" testing" + testURI)
|
||||||
resolved = true
|
if repoNode, ok := d.URIDirectory[testURI]; ok {
|
||||||
_, region, language := repoNode.GetLanguageAndRegionForURI(testURI)
|
resolved = true
|
||||||
log.Debug(" => " + testURIKey)
|
log.Debug(" => " + testURI)
|
||||||
log.Debug(" destination " + fmt.Sprint(repoNode.DestinationIds))
|
log.Debug(" destination " + fmt.Sprint(repoNode.DestinationId))
|
||||||
// check this one
|
if len(repoNode.DestinationId) > 0 {
|
||||||
// repoNode = repo.Directory[repoNode.DestinationIds]
|
if destionationNode, destinationNodeOk := d.Directory[repoNode.DestinationId]; destinationNodeOk {
|
||||||
|
repoNode = destionationNode
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
return true, testURI, dimension, repoNode
|
||||||
|
} else {
|
||||||
|
log.Debug(" => !" + testURI)
|
||||||
|
resolved = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, testURI, region, language, repoNode
|
|
||||||
} else {
|
|
||||||
log.Debug(" => !" + testURI)
|
|
||||||
resolved = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) GetItemMap(id string, dataFields []string) map[string]map[string]*content.Item {
|
func (repo *Repo) GetURIs(dimension string, ids []string) map[string]string {
|
||||||
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 {
|
|
||||||
uris := make(map[string]string)
|
uris := make(map[string]string)
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
uris[id] = repo.GetURI(region, language, id)
|
uris[id] = repo.GetURI(dimension, id)
|
||||||
}
|
}
|
||||||
return uris
|
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 {
|
if len(repoNode.LinkId) == 0 {
|
||||||
languageURIs, regionExists := repoNode.URIs[region]
|
return repoNode.URI
|
||||||
if regionExists {
|
|
||||||
languageURI, languageURIExists := languageURIs[language]
|
|
||||||
if languageURIExists {
|
|
||||||
return languageURI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
} else {
|
} 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 {
|
func (repo *Repo) GetURI(dimension string, id string) string {
|
||||||
repoNode, ok := repo.Directory[id]
|
repoNode, ok := repo.Directory[dimension].Directory[id]
|
||||||
if ok {
|
if ok {
|
||||||
return repo.GetURIForNode(region, language, repoNode)
|
return repo.GetURIForNode(dimension, repoNode)
|
||||||
}
|
}
|
||||||
return ""
|
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 := content.NewNode()
|
||||||
node.Item = repoNode.ToItem(region, language, dataFields)
|
node.Item = repoNode.ToItem(dataFields)
|
||||||
log.Debug("repo.GetNode: " + repoNode.Id)
|
log.Debug("repo.GetNode: " + repoNode.Id)
|
||||||
for _, childId := range repoNode.Index {
|
for _, childId := range repoNode.Index {
|
||||||
childNode := repoNode.Nodes[childId]
|
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) {
|
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, state, groups, region, language, dataFields)
|
node.Nodes[childId] = repo.GetNode(childNode, expanded, mimeTypes, path, level+1, groups, dataFields)
|
||||||
node.Index = append(node.Index, childId)
|
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)
|
path := make([]*content.Item, 0)
|
||||||
for nodeName, nodeRequest := range r.Nodes {
|
for nodeName, nodeRequest := range r.Nodes {
|
||||||
log.Debug(" adding node " + nodeName + " " + nodeRequest.Id)
|
log.Debug(" adding node " + nodeName + " " + nodeRequest.Id)
|
||||||
if treeNode, ok := repo.Directory[nodeRequest.Id]; ok {
|
if treeNode, ok := repo.Directory[nodeRequest.Dimension].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)
|
nodes[nodeName] = repo.GetNode(treeNode, nodeRequest.Expand, nodeRequest.MimeTypes, path, 0, r.Env.Groups, nodeRequest.DataFields)
|
||||||
} else {
|
} else {
|
||||||
log.Warning("you are requesting an invalid tree node for " + nodeName + " : " + nodeRequest.Id)
|
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 {
|
func (repo *Repo) GetContent(r *requests.Content) *content.SiteContent {
|
||||||
log.Debug("repo.GetContent: " + r.URI)
|
log.Debug("repo.GetContent: " + r.URI)
|
||||||
c := content.NewSiteContent()
|
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 {
|
if resolved {
|
||||||
log.Notice("200 for " + r.URI)
|
log.Notice("200 for " + r.URI)
|
||||||
// forbidden ?!
|
// forbidden ?!
|
||||||
c.Region = region
|
|
||||||
c.Language = language
|
|
||||||
c.Status = content.STATUS_OK
|
c.Status = content.STATUS_OK
|
||||||
c.Handler = node.Handler
|
c.MimeType = node.MimeType
|
||||||
|
c.Dimension = resolvedDimension
|
||||||
c.URI = resolvedURI
|
c.URI = resolvedURI
|
||||||
c.Item = node.ToItem(region, language, []string{})
|
c.Item = node.ToItem([]string{})
|
||||||
c.Path = node.GetPath(region, language)
|
c.Path = node.GetPath()
|
||||||
c.Data = node.Data
|
c.Data = node.Data
|
||||||
} else {
|
} else {
|
||||||
log.Notice("404 for " + r.URI)
|
log.Notice("404 for " + r.URI)
|
||||||
c.Status = content.STATUS_NOT_FOUND
|
c.Status = content.STATUS_NOT_FOUND
|
||||||
region = r.Env.Defaults.Region
|
c.Dimension = r.Env.Dimensions[0]
|
||||||
language = r.Env.Defaults.Language
|
|
||||||
}
|
}
|
||||||
for treeName, treeRequest := range r.Nodes {
|
for treeName, treeRequest := range r.Nodes {
|
||||||
log.Debug(" adding tree " + treeName + " " + treeRequest.Id)
|
log.Debug(" adding tree " + treeName + " " + treeRequest.Id)
|
||||||
if treeNode, ok := repo.Directory[treeRequest.Id]; ok {
|
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.State, r.Env.Groups, region, language, treeRequest.DataFields)
|
c.Nodes[treeName] = repo.GetNode(treeNode, treeRequest.Expand, treeRequest.MimeTypes, c.Path, 0, r.Env.Groups, treeRequest.DataFields)
|
||||||
} else {
|
} else {
|
||||||
log.Warning("you are requesting an invalid tree node for " + treeName + " : " + treeRequest.Id)
|
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
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func (repo *Repo) GetRepo() *content.RepoNode {
|
func (repo *Repo) GetRepo() *content.RepoNode {
|
||||||
return repo.Node
|
return repo.Node
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
func uriKeyForState(state string, uri string) string {
|
func uriKeyForState(state string, uri string) string {
|
||||||
return state + "-" + uri
|
return state + "-" + uri
|
||||||
}
|
}
|
||||||
@ -222,30 +209,10 @@ func builDirectory(dirNode *content.RepoNode, directory map[string]*content.Repo
|
|||||||
}
|
}
|
||||||
directory[dirNode.Id] = dirNode
|
directory[dirNode.Id] = dirNode
|
||||||
//todo handle duplicate uris
|
//todo handle duplicate uris
|
||||||
for _, languageURIs := range dirNode.URIs {
|
if _, thereIsAnExistingUriNode := uRIDirectory[dirNode.URI]; thereIsAnExistingUriNode {
|
||||||
for _, uri := range languageURIs {
|
return errors.New("duplicate node with uri: " + dirNode.URI)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
uRIDirectory[dirNode.URI] = dirNode
|
||||||
for _, childNode := range dirNode.Nodes {
|
for _, childNode := range dirNode.Nodes {
|
||||||
err := builDirectory(childNode, directory, uRIDirectory)
|
err := builDirectory(childNode, directory, uRIDirectory)
|
||||||
if err != nil {
|
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 {
|
func wireAliases(directory map[string]*content.RepoNode) error {
|
||||||
// validation ?!
|
|
||||||
for _, repoNode := range directory {
|
for _, repoNode := range directory {
|
||||||
if len(repoNode.LinkIds) > 0 {
|
if len(repoNode.LinkId) > 0 {
|
||||||
for region, languages := range repoNode.LinkIds {
|
if destinationNode, ok := directory[repoNode.LinkId]; ok {
|
||||||
for language, linkId := range languages {
|
repoNode.URI = destinationNode.URI
|
||||||
if destinationNode, ok := directory[linkId]; ok {
|
} else {
|
||||||
repoNode.URIs[region][language] = destinationNode.URIs[region][language]
|
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 {
|
func (repo *Repo) Update() *responses.Update {
|
||||||
updateResponse := responses.NewUpdate()
|
updateResponse := responses.NewUpdate()
|
||||||
newNode := content.NewRepoNode()
|
newNodes := make(map[string]*content.RepoNode) //content.NewRepoNode()
|
||||||
startTimeRepo := time.Now()
|
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()
|
updateResponse.Stats.RepoRuntime = time.Now().Sub(startTimeRepo).Seconds()
|
||||||
startTimeOwn := time.Now()
|
startTimeOwn := time.Now()
|
||||||
updateResponse.Success = ok
|
updateResponse.Success = ok
|
||||||
if ok {
|
if ok {
|
||||||
repo.Load(newNode)
|
for dimension, newNode := range newNodes {
|
||||||
updateResponse.Stats.NumberOfNodes = len(repo.Directory)
|
repo.Load(dimension, newNode)
|
||||||
updateResponse.Stats.NumberOfURIs = len(repo.URIDirectory)
|
updateResponse.Stats.NumberOfNodes = len(repo.Directory[dimension].Directory)
|
||||||
|
updateResponse.Stats.NumberOfURIs = len(repo.Directory[dimension].URIDirectory)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error(fmt.Sprintf("update error: %", err))
|
log.Error(fmt.Sprintf("update error: %", err))
|
||||||
updateResponse.ErrorMessage = fmt.Sprintf("%", err)
|
updateResponse.ErrorMessage = fmt.Sprintf("%", err)
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
package requests
|
package requests
|
||||||
|
|
||||||
type Content struct {
|
type Content struct {
|
||||||
Env *Env `json:"env"`
|
Env *Env `json:"env"`
|
||||||
URI string
|
URI string `json:"URI"`
|
||||||
Nodes map[string]*Node `json:"nodes"`
|
Nodes map[string]*Node `json:"nodes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,14 @@
|
|||||||
package requests
|
package requests
|
||||||
|
|
||||||
type Defaults struct {
|
|
||||||
Region string `json:"region"`
|
|
||||||
Language string `json:"language"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Env struct {
|
type Env struct {
|
||||||
Defaults *Defaults `json:"defaults"`
|
Dimensions []string `json:"dimensions"`
|
||||||
Groups []string `json:"groups"`
|
Groups []string `json:"groups"`
|
||||||
State string
|
Data interface{} `json:"data"`
|
||||||
Data interface{} `json:"data"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
Dimension string `json:"id"`
|
||||||
MimeTypes []string `json:"mimeTypes"`
|
MimeTypes []string `json:"mimeTypes"`
|
||||||
Expand bool `json:"expand"`
|
Expand bool `json:"expand"`
|
||||||
DataFields []string `json:"dataFields"`
|
DataFields []string `json:"dataFields"`
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
package requests
|
package requests
|
||||||
|
|
||||||
type URIs struct {
|
type URIs struct {
|
||||||
Ids []string `json:"ids"`
|
Ids []string `json:"ids"`
|
||||||
Region string `json:"region"`
|
Dimension string `json:"dimension"`
|
||||||
Language string `json:"language"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewURIs() *URIs {
|
func NewURIs() *URIs {
|
||||||
|
|||||||
@ -32,7 +32,7 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
|||||||
getURIRequest := requests.NewURIs()
|
getURIRequest := requests.NewURIs()
|
||||||
jsonErr = json.Unmarshal(jsonBuffer, &getURIRequest)
|
jsonErr = json.Unmarshal(jsonBuffer, &getURIRequest)
|
||||||
log.Debug(" getURIRequest: " + fmt.Sprint(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))
|
log.Debug(" resolved: " + fmt.Sprint(uris))
|
||||||
reply = uris
|
reply = uris
|
||||||
break
|
break
|
||||||
@ -43,13 +43,15 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
|||||||
content := contentRepo.GetContent(contentRequest)
|
content := contentRepo.GetContent(contentRequest)
|
||||||
reply = content
|
reply = content
|
||||||
break
|
break
|
||||||
case "getItemMap":
|
/*
|
||||||
itemMapRequest := requests.NewItemMap()
|
case "getItemMap":
|
||||||
jsonErr = json.Unmarshal(jsonBuffer, &itemMapRequest)
|
itemMapRequest := requests.NewItemMap()
|
||||||
log.Debug(" itemMapRequest: " + fmt.Sprint(itemMapRequest))
|
jsonErr = json.Unmarshal(jsonBuffer, &itemMapRequest)
|
||||||
itemMap := contentRepo.GetItemMap(itemMapRequest.Id, itemMapRequest.DataFields)
|
log.Debug(" itemMapRequest: " + fmt.Sprint(itemMapRequest))
|
||||||
reply = itemMap
|
itemMap := contentRepo.GetItemMap(itemMapRequest.Id, itemMapRequest.DataFields)
|
||||||
break
|
reply = itemMap
|
||||||
|
break
|
||||||
|
*/
|
||||||
case "getNodes":
|
case "getNodes":
|
||||||
nodesRequest := requests.NewNodes()
|
nodesRequest := requests.NewNodes()
|
||||||
jsonErr = json.Unmarshal(jsonBuffer, &nodesRequest)
|
jsonErr = json.Unmarshal(jsonBuffer, &nodesRequest)
|
||||||
@ -64,13 +66,15 @@ func handleSocketRequest(handler string, jsonBuffer []byte) (replyBytes []byte,
|
|||||||
updateResponse := contentRepo.Update()
|
updateResponse := contentRepo.Update()
|
||||||
reply = updateResponse
|
reply = updateResponse
|
||||||
break
|
break
|
||||||
case "getRepo":
|
/*
|
||||||
repoRequest := requests.NewRepo()
|
case "getRepo":
|
||||||
jsonErr = json.Unmarshal(jsonBuffer, &repoRequest)
|
repoRequest := requests.NewRepo()
|
||||||
log.Debug(" getRepoRequest: " + fmt.Sprint(repoRequest))
|
jsonErr = json.Unmarshal(jsonBuffer, &repoRequest)
|
||||||
repoResponse := contentRepo.GetRepo()
|
log.Debug(" getRepoRequest: " + fmt.Sprint(repoRequest))
|
||||||
reply = repoResponse
|
repoResponse := contentRepo.GetRepo()
|
||||||
break
|
reply = repoResponse
|
||||||
|
break
|
||||||
|
*/
|
||||||
default:
|
default:
|
||||||
err = errors.New(log.Error(" can not handle this one " + handler))
|
err = errors.New(log.Error(" can not handle this one " + handler))
|
||||||
errorResponse := responses.NewError(1, "unkown handler")
|
errorResponse := responses.NewError(1, "unkown handler")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user