pango2 template engine
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Arnas Udovicius 2022-08-20 23:46:31 +03:00
parent 0cf5eb4d40
commit 37cb244ffb
14 changed files with 320 additions and 165 deletions

View file

@ -38,3 +38,4 @@ __DONE__
* about
* migrate to gRPC
* routing, not found
* template engine

View file

@ -1,9 +1,43 @@
package main
import (
"errors"
"net/url"
"sort"
"strings"
)
func (file *TreeFile) CategoriesAsUrl() string {
escapedCategories := []string{}
for _, c := range file.Category {
escapedCategories = append(escapedCategories, url.QueryEscape(c))
}
return strings.Join(escapedCategories, "/")
}
func (file *TreeFile) GmiName() string {
return strings.Replace(file.Name, ".md", ".gmi", 1)
}
func (tree *Tree) GetIndexFile() (*TreeFile, error) {
for _, file := range tree.RootFiles {
if file.Name == "index.md" {
return file, nil
}
}
return nil, errors.New("index file not found")
}
func (tree *Tree) HasIndexFile() bool {
_, err := tree.GetIndexFile()
if err != nil {
return false
}
return true
}
func GetLastFiles(files []*TreeFile) []*TreeFile {
sortingFiles := make(map[string]*TreeFile)
for _, f := range files {

1
go.mod
View file

@ -4,6 +4,7 @@ go 1.18
require (
git.sr.ht/~adnano/go-gemini v0.2.3
github.com/flosch/pongo2/v6 v6.0.0
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.1
)

5
go.sum
View file

@ -20,6 +20,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flosch/pongo2/v6 v6.0.0 h1:lsGru8IAzHgIAw6H2m4PCyleO58I40ow6apih0WprMU=
github.com/flosch/pongo2/v6 v6.0.0/go.mod h1:CuDpFm47R0uGGE7z13/tTlt1Y6zdxvr2RLT5LJhsHEU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -47,6 +49,8 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@ -126,6 +130,7 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

285
main.go
View file

@ -6,13 +6,13 @@ import (
"fmt"
"google.golang.org/grpc/credentials/insecure"
"log"
"os"
"regexp"
"strings"
"time"
"git.sr.ht/~adnano/go-gemini"
"git.sr.ht/~adnano/go-gemini/certificate"
"github.com/flosch/pongo2/v6"
"google.golang.org/grpc"
)
@ -62,7 +62,10 @@ func main() {
func processFavicon(_ context.Context, w gemini.ResponseWriter, _ *gemini.Request) {
w.SetMediaType("text/plain")
w.Write([]byte("\U0001F31B"))
_, err := w.Write([]byte("\U0001F31B"))
if err != nil {
w.WriteHeader(gemini.StatusNotFound, "Out of space")
}
}
func process(_ context.Context, w gemini.ResponseWriter, r *gemini.Request) {
@ -93,12 +96,175 @@ func process(_ context.Context, w gemini.ResponseWriter, r *gemini.Request) {
renderSearch(lang, w, r, client)
case regexp.MustCompile(`^/(sgs|en)/f/?$`).MatchString(r.URL.Path):
renderAllFiles(lang, w, client)
case regexp.MustCompile(`^/(sgs|en)/f/([\p{L}\d_+.]+/)+[\d\w]+/[\w_]+.gmi$`).MatchString(r.URL.Path):
renderFile(lang, w, r, client)
case regexp.MustCompile(`^/(sgs|en)/f/[\p{L}\d_+.]+(/[\p{L}\d_+.]+)*/?$`).MatchString(r.URL.Path):
renderCategory(lang, w, r, client)
default:
w.WriteHeader(gemini.StatusNotFound, "Out of space")
}
}
func renderIndex(lang string, w gemini.ResponseWriter, client TreeManagerClient) {
langFilter := TreeRequest_Filter{Key: "lang", Value: lang}
filters := []*TreeRequest_Filter{&langFilter}
path := ""
tr := TreeRequest{Path: &path, Filter: filters}
tree, err := client.GetSummery(context.Background(), &tr)
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
w.SetMediaType("text/gemini")
tpl := pongo2.Must(pongo2.FromFile(fmt.Sprintf("templates/%s/index.gmi", lang)))
page, err := tpl.Execute(pongo2.Context{"tree": tree, "lang": lang, "lastFiles": GetLastFiles(tree.Files)})
if err != nil {
log.Fatalf("template failed: %v", err)
return
}
_, err = w.Write([]byte(page))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
}
func renderAbout(lang string, w gemini.ResponseWriter) {
w.SetMediaType("text/gemini")
tpl := pongo2.Must(pongo2.FromFile(fmt.Sprintf("templates/%s/about.gmi", lang)))
page, err := tpl.Execute(pongo2.Context{})
if err != nil {
log.Fatalf("template failed: %v", err)
return
}
_, err = w.Write([]byte(page))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
}
}
func renderSearch(lang string, w gemini.ResponseWriter, r *gemini.Request, client TreeManagerClient) {
q, err := gemini.QueryUnescape(r.URL.RawQuery)
if err != nil || q == "" {
searchStr := "Input searching tag, created date or word in description"
if lang == "sgs" {
searchStr = "Ivesk ėiškuoma žīma, sokūrėma data arba žuodi ėš aprašīma"
}
w.WriteHeader(gemini.StatusInput, searchStr)
return
}
descFilter := TreeRequest_Filter{Key: "description", Value: q}
createdFilter := TreeRequest_Filter{Key: "created", Value: q}
tagFilter := TreeRequest_Filter{Key: "tag", Value: q}
filters := []*TreeRequest_Filter{&descFilter, &createdFilter, &tagFilter}
path := ""
tr := TreeRequest{Path: &path, Filter: filters}
tree, err := client.GetSummery(context.Background(), &tr)
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
w.SetMediaType("text/gemini")
tpl := pongo2.Must(pongo2.FromFile("templates/search.gmi"))
page, err := tpl.Execute(pongo2.Context{"lang": lang, "tree": tree, "q": q})
if err != nil {
log.Fatalf("template failed: %v", err)
return
}
_, err = w.Write([]byte(page))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
}
func renderCategory(lang string, w gemini.ResponseWriter, r *gemini.Request, client TreeManagerClient) {
urlParts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
path := "/" + strings.Join(urlParts[2:], "/")
tr := TreeRequest{Path: &path, Filter: []*TreeRequest_Filter{}}
tree, err := client.GetSummery(context.Background(), &tr)
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
indexFile, err := tree.GetIndexFile()
var file *FileContent
if err == nil {
fr := FileRequest{Id: indexFile.Id}
file, err = client.GetFile(context.Background(), &fr)
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
}
w.SetMediaType("text/gemini")
tpl := pongo2.Must(pongo2.FromFile("templates/category.gmi"))
fmt.Println(file, &file)
page, err := tpl.Execute(pongo2.Context{"lang": lang, "tree": tree, "path": path, "indexFile": file})
if err != nil {
log.Fatalf("template failed: %v", err)
return
}
_, err = w.Write([]byte(page))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
}
func renderFile(lang string, w gemini.ResponseWriter, r *gemini.Request, client TreeManagerClient) {
urlParts := strings.Split(r.URL.Path, "/")
id := urlParts[len(urlParts)-2]
fr := FileRequest{Id: id}
file, err := client.GetFile(context.Background(), &fr)
if err != nil {
log.Fatalf("client.GetSummery failed: %v", err)
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
category := ""
for i, cat := range file.File.Category {
category = category + fmt.Sprintf("=> /%s/f/%s .%s└─ %s\n",
lang,
strings.Join(file.File.Category[:i+1], "/"),
strings.Repeat(" ", i),
cat,
)
}
content := fmt.Sprintf(
"# %s\n\n"+
"%s\n\n"+
"%s\n%s\n\n"+
"%s\n\n[ %s ]",
file.File.Description,
file.Content,
file.File.Created,
file.File.Copyright,
category,
strings.Join(file.File.Tags, " "),
)
w.Write([]byte(content))
}
func renderAllFiles(lang string, w gemini.ResponseWriter, client TreeManagerClient) {
langFilter := TreeRequest_Filter{Key: "lang", Value: lang}
filters := []*TreeRequest_Filter{&langFilter}
@ -121,15 +287,7 @@ func renderAllFiles(lang string, w gemini.ResponseWriter, client TreeManagerClie
}
for _, f := range tree.Files {
content = content + fmt.Sprintf(
"=> /%s/f/%s/%s/%s %s (%s)\n",
lang,
strings.Join(f.Category, "/"),
f.Id,
strings.Replace(f.Name, ".md", ".gmi", 1),
f.Description,
f.Created,
)
content = appendFileLink(lang, content, f)
}
if lang == "sgs" {
@ -141,98 +299,15 @@ func renderAllFiles(lang string, w gemini.ResponseWriter, client TreeManagerClie
w.Write([]byte(content))
}
func renderSearch(lang string, w gemini.ResponseWriter, r *gemini.Request, client TreeManagerClient) {
q, err := gemini.QueryUnescape(r.URL.RawQuery)
if err != nil || q == "" {
searchStr := "Input searching tag, created date or word in description"
if lang == "sgs" {
searchStr = "Ivesk ėiškuoma žīma, sokūrėma data arba žuodi ėš aprašīma"
}
w.WriteHeader(gemini.StatusInput, searchStr)
return
}
langFilter := TreeRequest_Filter{Key: "lang", Value: lang}
descFilter := TreeRequest_Filter{Key: "description", Value: lang}
createdFilter := TreeRequest_Filter{Key: "created", Value: lang}
tagFilter := TreeRequest_Filter{Key: "tag", Value: lang}
filters := []*TreeRequest_Filter{&langFilter, &descFilter, &createdFilter, &tagFilter}
path := ""
tr := TreeRequest{Path: &path, Filter: filters}
tree, err := client.GetSummery(context.Background(), &tr)
if err != nil {
log.Fatalf("client.GetSummery failed: %v", err)
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
fmt.Println(tree)
w.Write([]byte("Nieka narada dā\n" +
"=> / ← back"))
}
func renderAbout(lang string, w gemini.ResponseWriter) {
w.SetMediaType("text/gemini")
content, err := os.ReadFile(fmt.Sprintf("templates/%s/about.gmi", lang))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
_, err = w.Write(content)
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
}
func renderIndex(lang string, w gemini.ResponseWriter, client TreeManagerClient) {
w.SetMediaType("text/gemini")
content, err := os.ReadFile(fmt.Sprintf("templates/%s/index.gmi", lang))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
page := string(content)
langFilter := TreeRequest_Filter{Key: "lang", Value: lang}
filters := []*TreeRequest_Filter{&langFilter}
path := ""
tr := TreeRequest{Path: &path, Filter: filters}
tree, err := client.GetSummery(context.Background(), &tr)
if err != nil {
log.Fatalf("client.GetSummery failed: %v", err)
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
categories := ""
for c, count := range tree.Categories {
categories = categories + fmt.Sprintf("=> /%s/f/%s %s (%d)\n", lang, c, c, count)
}
page = strings.Replace(page, "{{categories}}", categories, 1)
tags := ""
for t, count := range tree.Tags {
tags = tags + fmt.Sprintf("=> /%s/t/%s %s (%d)\n", lang, t, t, count)
}
page = strings.Replace(page, "{{tags}}", tags, 1)
lastFiles := ""
for _, f := range GetLastFiles(tree.Files) {
lastFiles = lastFiles + fmt.Sprintf(
"=> /%s/f/%s/%s/%s %s (%s)\n",
lang, strings.Join(f.Category, "/"), f.Id, strings.Replace(f.Name, ".md", ".gmi", 1), f.Description, f.Created,
)
}
page = strings.Replace(page, "{{last_posts}}", lastFiles, 1)
_, err = w.Write([]byte(page))
if err != nil {
w.WriteHeader(gemini.StatusTemporaryFailure, "Internal server error")
return
}
func appendFileLink(lang string, content string, f *TreeFile) string {
content = content + fmt.Sprintf(
"=> /%s/f/%s/%s/%s %s (%s)\n",
lang,
strings.Join(f.Category, "/"),
f.Id,
strings.Replace(f.Name, ".md", ".gmi", 1),
f.Description,
f.Created,
)
return content
}

10
templates/category.gmi Normal file
View file

@ -0,0 +1,10 @@
{% import "macros.tpl" category_url, text_url %}
# Arna alkierios :: {{ path }}
{% if indexFile %}{{ indexFile.Content }}{% endif %}
{% for file in tree.RootFiles %}{{ text_url(lang, file) }} {% endfor %}
{% if tree.Categories %}### {% if lang == "sgs" %}Kateguorėjės{% else %}Categories{% endif %}
{% for cat, count in tree.Categories %}{{ category_url(lang, cat, cat, count) }}
{% endfor %} {% endif %}
=> {% if lang == "sgs" %}/sgs 🏠 nomėi{% else %}/en 🏠 home{% endif %}

View file

@ -27,7 +27,7 @@ Articles I wrote simply in files and put them in my self-hosted cloud by created
From this service it is served to gemini service what is written in Go, too, or to http service (backend on Go, frontend on Vue.js). For communications I use gRPC.
=> /en/f/gemini/arns-lt more...
=> /en/f/gemini/arns_lt more...
=> https://g.arns.lt/zordsdavini/zord-tree zord-tree library to build tree from files
=> https://g.arns.lt/zordsdavini/arns-lt-tree-push-service service written on top of zord-tree to serve files
=> https://g.arns.lt/zordsdavini/arns-lt-gemini gemini service

View file

@ -1,3 +1,4 @@
{% import "../macros.tpl" category_url, tag_url, text_url %}
# Arna alkierios
Welcome to my capsule in Gemini space.
@ -12,16 +13,16 @@ Main themes are spreaded by categories. Each file may have tags what can filter
=> /en/s search
=> /en/a about
### Categories
{% if tree.Categories %}### Categories
{% for cat, count in tree.Categories %}
{{ category_url(lang, cat, cat, count) }} {% endfor %} {% endif %}
{{categories}}
{% if tree.Tags %}### Tags
{% for tag, count in tree.Tags %}
{{ tag_url(lang, tag, count) }} {% endfor %} {% endif %}
### Tags
{{tags}}
### Last posts
{{last_posts}}
{% if lastFiles %}### Last texts
{% for file in lastFiles %}
{{ text_url(lang, file) }} {% endfor %} {% endif %}
=> /en/f all texts

5
templates/macros.tpl Normal file
View file

@ -0,0 +1,5 @@
{% macro category_url(lang, path, category, count) export %}=> /{{ lang }}/f/{{ path }} {{ category }} ({{ count }}) {% endmacro %}
{% macro tag_url(lang, tag, count) export %}=> /{{ lang }}/t/{{ tag }} {{ tag }} ({{ count }}) {% endmacro %}
{% macro text_url(lang, file) export %}=> /{{ lang }}/f/{{ file.CategoriesAsUrl() }}/{{ file.Id }}/{{ file.GmiName() }} {{ file.Description }} ({{ file.Created }}) {% endmacro %}

9
templates/search.gmi Normal file
View file

@ -0,0 +1,9 @@
{% import "macros.tpl" text_url %}
# Arna alkierios :: {% if lang == "sgs" %}Paėiška{% else %}Search{% endif %}
{% if lang == "sgs" %}Ėiškuota vagol{% else %}Searched by{% endif %}: {{ q }}
{% if tree.Files|length == 0 %}{% if lang == "sgs" %}Nieka narada{% else %}Nothing found{% endif %}...{% else %}
{% for file in tree.Files %}
{{ text_url(lang, file) }} {% endfor %} {% endif %}
=> {% if lang == "sgs" %}/sgs ← grīžtė{% else %}/en ← back{% endif %}

View file

@ -27,7 +27,7 @@ Tekstus rašau i paprastiausius failiokus ėr anus talpėno sava „cloud'ė“
Jau ėš makliavuonės servėsa pajemo i gemini servėsa, katras parašīts ėrgė so Go, arba i http servėsa (backend's ont Go REST, frontend's ont Vue.js). Ruodā nauduojo gRPC pruotuokuola.
=> /en/f/gemini/arns-lt platiau (onglėškā)
=> /en/f/gemini/arns_lt platiau (onglėškā)
=> https://g.arns.lt/zordsdavini/zord-tree zord-tree bėbliuoteka sokortė miedi ėš failu
=> https://g.arns.lt/zordsdavini/arns-lt-tree-push-service servėsos ont zord-tree somakliavuotė failus ėr anus padoutė tuoliau
=> https://g.arns.lt/zordsdavini/arns-lt-gemini gemini servėsos

View file

@ -1,3 +1,4 @@
{% import "../macros.tpl" category_url, tag_url, text_url %}
# Arna alkierios
Sveikė atvīkėn i mona kapsolė Gemini ertie.
@ -12,16 +13,16 @@ Pagrindėnės temas paskėrstītas par kateguorėjės. Kuožnos fails gal turie
=> /sgs/s ėiškuok
=> /sgs/a aple
### Kateguorėjės
{% if tree.Categories %}### Kateguorėjės
{% for cat, count in tree.Categories %}
{{ category_url(lang, cat, cat, count) }} {% endfor %} {% endif %}
{{categories}}
{% if tree.Tags %}### Žīmas
{% for tag, count in tree.Tags %}
{{ tag_url(lang, tag, count) }} {% endfor %} {% endif %}
### Žīmas
{{tags}}
### Paskotėnē īrašā
{{last_posts}}
{% if lastFiles %}### Paskotėnē īrašā
{% for file in lastFiles %}
{{ text_url(lang, file) }} {% endfor %} {% endif %}
=> /sgs/f vėsė straipsnē

View file

@ -231,6 +231,7 @@ type Tree struct {
unknownFields protoimpl.UnknownFields
Files []*TreeFile `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
RootFiles []*TreeFile `protobuf:"bytes,4,rep,name=rootFiles,proto3" json:"rootFiles,omitempty"`
Tags map[string]int32 `protobuf:"bytes,2,rep,name=tags,proto3" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
Categories map[string]int32 `protobuf:"bytes,3,rep,name=categories,proto3" json:"categories,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
}
@ -274,6 +275,13 @@ func (x *Tree) GetFiles() []*TreeFile {
return nil
}
func (x *Tree) GetRootFiles() []*TreeFile {
if x != nil {
return x.RootFiles
}
return nil
}
func (x *Tree) GetTags() map[string]int32 {
if x != nil {
return x.Tags
@ -426,36 +434,39 @@ var file_tree_proto_rawDesc = []byte{
0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73,
0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x18, 0x0a, 0x07,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x8a, 0x02, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12,
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0xb8, 0x02, 0x0a, 0x04, 0x54, 0x72, 0x65, 0x65, 0x12,
0x24, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x2e,
0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12,
0x3a, 0x0a, 0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x2e,
0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x54,
0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69,
0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x22, 0x4b, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65,
0x6e, 0x74, 0x12, 0x22, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x0e, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x65,
0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
0x32, 0x6f, 0x0a, 0x0b, 0x54, 0x72, 0x65, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12,
0x2d, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x79, 0x12, 0x11, 0x2e,
0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x0a, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x22, 0x00, 0x12, 0x31,
0x0a, 0x07, 0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x69, 0x6e,
0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d,
0x61, 0x69, 0x6e, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22,
0x00, 0x42, 0x03, 0x5a, 0x01, 0x2e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x46, 0x69, 0x6c,
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e,
0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x46, 0x69,
0x6c, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x14, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x2e, 0x54, 0x61,
0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x3a, 0x0a,
0x0a, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x2e, 0x43, 0x61,
0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x63,
0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x1a, 0x3d, 0x0a, 0x0f, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0x4b, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
0x12, 0x22, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04,
0x66, 0x69, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0x6f,
0x0a, 0x0b, 0x54, 0x72, 0x65, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x2d, 0x0a,
0x0a, 0x47, 0x65, 0x74, 0x53, 0x75, 0x6d, 0x6d, 0x65, 0x72, 0x79, 0x12, 0x11, 0x2e, 0x6d, 0x61,
0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a,
0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x07,
0x47, 0x65, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x11, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x46,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x6d, 0x61, 0x69,
0x6e, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x42,
0x03, 0x5a, 0x01, 0x2e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -484,18 +495,19 @@ var file_tree_proto_goTypes = []interface{}{
var file_tree_proto_depIdxs = []int32{
5, // 0: main.TreeRequest.filter:type_name -> main.TreeRequest.Filter
2, // 1: main.Tree.files:type_name -> main.TreeFile
6, // 2: main.Tree.tags:type_name -> main.Tree.TagsEntry
7, // 3: main.Tree.categories:type_name -> main.Tree.CategoriesEntry
2, // 4: main.FileContent.file:type_name -> main.TreeFile
1, // 5: main.TreeManager.GetSummery:input_type -> main.TreeRequest
0, // 6: main.TreeManager.GetFile:input_type -> main.FileRequest
3, // 7: main.TreeManager.GetSummery:output_type -> main.Tree
4, // 8: main.TreeManager.GetFile:output_type -> main.FileContent
7, // [7:9] is the sub-list for method output_type
5, // [5:7] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
2, // 2: main.Tree.rootFiles:type_name -> main.TreeFile
6, // 3: main.Tree.tags:type_name -> main.Tree.TagsEntry
7, // 4: main.Tree.categories:type_name -> main.Tree.CategoriesEntry
2, // 5: main.FileContent.file:type_name -> main.TreeFile
1, // 6: main.TreeManager.GetSummery:input_type -> main.TreeRequest
0, // 7: main.TreeManager.GetFile:input_type -> main.FileRequest
3, // 8: main.TreeManager.GetSummery:output_type -> main.Tree
4, // 9: main.TreeManager.GetFile:output_type -> main.FileContent
8, // [8:10] is the sub-list for method output_type
6, // [6:8] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_tree_proto_init() }

View file

@ -39,6 +39,7 @@ message TreeFile {
message Tree {
repeated TreeFile files = 1;
repeated TreeFile rootFiles = 4;
map<string, int32> tags = 2;
map<string, int32> categories = 3;
}