diff --git a/.dockerignore b/.dockerignore index 4b910a2..5de0ae6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,7 @@ * +!cmd !nginx -!frontend +!pkg !web !go.mod !go.sum diff --git a/.github/workflows/image-make-and-publish.yml b/.github/workflows/image-make-and-publish.yml index beb86f3..5433a76 100644 --- a/.github/workflows/image-make-and-publish.yml +++ b/.github/workflows/image-make-and-publish.yml @@ -3,7 +3,9 @@ name: Docker on: workflow_dispatch: push: - branches: [ main ] + branches: + - 'main' + - 'develop' env: REGISTRY: ghcr.io @@ -22,6 +24,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + - name: Install cosign if: github.event_name != 'pull_request' uses: sigstore/cosign-installer@main @@ -37,17 +44,38 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Get date as semver + id: calver + env: + REF_NAME: ${{ github.ref_name }} + run: | + python -c " + from datetime import datetime, timedelta + from os import environ + ref = environ['REF_NAME'] + now = datetime.now() + date = now.strftime('%y.%m.%d') + delta = timedelta(hours=now.hour,minutes=now.minute,seconds=now.second) + print(f'::set-output name=current::{date}-{ref}.{delta.seconds}') + " + - name: Extract Docker metadata id: meta uses: docker/metadata-action@v3 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=${{ steps.calver.outputs.current }} + type=raw,value=${{ github.ref_name }} + type=sha - name: Build and push Docker image id: build-and-push uses: docker/build-push-action@v2 with: context: . + build-args: | + APP_VERSION=${{ steps.calver.outputs.current }} push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 48fe088..bb09166 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,13 +16,14 @@ RUN --mount=type=cache,id=gopath,target=${GOPATH} \ ARG APP_VERSION=containerized -COPY frontend frontend +COPY cmd cmd +COPY pkg pkg RUN --mount=type=cache,id=gopath,target=${GOPATH} \ go build \ -o nikita-tokarch-uk-frontend \ -ldflags "-X main.Version=${APP_VERSION}" \ - code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend + code.tokarch.uk/mainnika/nikita-tokarch-uk/cmd/renderer FROM registry.access.redhat.com/ubi8/ubi as js-builder diff --git a/chart/.helmignore b/chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/chart/Chart.yaml b/chart/Chart.yaml new file mode 100644 index 0000000..9913327 --- /dev/null +++ b/chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: nikita-tokarch-uk +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: main diff --git a/chart/templates/NOTES.txt b/chart/templates/NOTES.txt new file mode 100644 index 0000000..08b11fa --- /dev/null +++ b/chart/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nikita-tokarch-uk.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "nikita-tokarch-uk.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nikita-tokarch-uk.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "nikita-tokarch-uk.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl new file mode 100644 index 0000000..9a2f659 --- /dev/null +++ b/chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "nikita-tokarch-uk.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "nikita-tokarch-uk.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "nikita-tokarch-uk.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "nikita-tokarch-uk.labels" -}} +helm.sh/chart: {{ include "nikita-tokarch-uk.chart" . }} +{{ include "nikita-tokarch-uk.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "nikita-tokarch-uk.selectorLabels" -}} +app.kubernetes.io/name: {{ include "nikita-tokarch-uk.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "nikita-tokarch-uk.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "nikita-tokarch-uk.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/chart/templates/config.yaml b/chart/templates/config.yaml new file mode 100644 index 0000000..d50b017 --- /dev/null +++ b/chart/templates/config.yaml @@ -0,0 +1,10 @@ +{{- if .Values.config -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ include "nikita-tokarch-uk.fullname" . }}-config" + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} +data: + {{- toYaml .Values.config | nindent 2 }} +{{- end }} \ No newline at end of file diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml new file mode 100644 index 0000000..30dc23e --- /dev/null +++ b/chart/templates/deployment.yaml @@ -0,0 +1,84 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "nikita-tokarch-uk.fullname" . }} + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "nikita-tokarch-uk.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include ( print $.Template.BasePath "/config.yaml" ) . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "nikita-tokarch-uk.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "nikita-tokarch-uk.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /usr/sbin/nginx + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: /version.html + port: http + readinessProbe: + httpGet: + path: /version.html + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + - name: {{ .Chart.Name }}-renderer + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + workingDir: /etc/nikita-tokarch-uk + command: + - /usr/local/bin/nikita-tokarch-uk-frontend + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: "{{ include "nikita-tokarch-uk.fullname" . }}-config" + mountPath: /etc/nikita-tokarch-uk + readOnly: true + volumes: + - name: "{{ template "nikita-tokarch-uk.fullname" . }}-config" + {{- if .Values.config }} + configMap: + name: "{{ include "nikita-tokarch-uk.fullname" . }}-config" + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/chart/templates/ingress.yaml b/chart/templates/ingress.yaml new file mode 100644 index 0000000..9faeddb --- /dev/null +++ b/chart/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "nikita-tokarch-uk.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/chart/templates/service.yaml b/chart/templates/service.yaml new file mode 100644 index 0000000..f84980c --- /dev/null +++ b/chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "nikita-tokarch-uk.fullname" . }} + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "nikita-tokarch-uk.selectorLabels" . | nindent 4 }} diff --git a/chart/templates/serviceaccount.yaml b/chart/templates/serviceaccount.yaml new file mode 100644 index 0000000..9a06736 --- /dev/null +++ b/chart/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "nikita-tokarch-uk.serviceAccountName" . }} + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/tests/test-connection.yaml b/chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000..2cc2ffd --- /dev/null +++ b/chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "nikita-tokarch-uk.fullname" . }}-test-connection" + labels: + {{- include "nikita-tokarch-uk.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "nikita-tokarch-uk.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/chart/values.yaml b/chart/values.yaml new file mode 100644 index 0000000..7c4aac0 --- /dev/null +++ b/chart/values.yaml @@ -0,0 +1,77 @@ +# Default values for nikita-tokarch-uk. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# config: +# frontend.yaml: |- + +replicaCount: 1 + +image: + repository: ghcr.io/mainnika/nikita-tokarch-uk + pullPolicy: Always + # tag: "main" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: false + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: true + className: "nginx" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: nikita.tokarch.uk + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/frontend/main.go b/cmd/renderer/main.go similarity index 73% rename from frontend/main.go rename to cmd/renderer/main.go index a15f26d..43e93e7 100644 --- a/frontend/main.go +++ b/cmd/renderer/main.go @@ -9,11 +9,10 @@ import ( "github.com/spf13/viper" "github.com/valyala/fasthttp" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/config" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/renderer" - - _ "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/config" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/v4api/httpclient" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/routes" + _ "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates" ) var Version = "nightly" @@ -53,14 +52,15 @@ func main() { logrus.Fatal(err) } - ghostClient := &ghost.HTTPClient{ - Addr: config.Content.Backend, + ghostClient := &httpclient.HTTPClient{ + Addr: config.Content.Backend.Addr, + Secured: config.Content.Backend.Secured, + Headers: config.Content.Backend.Headers, ContentKey: config.Content.Key, - Secured: true, QueryTimeout: time.Second, } - rendererHandler := &renderer.Renderer{ + apiRoutes := &routes.Routes{ GhostClient: ghostClient, ContentConfig: config.Content, Base: config.Base, @@ -68,7 +68,7 @@ func main() { httpServer := fasthttp.Server{ Logger: logrus.StandardLogger(), - Handler: rendererHandler.Handler, + Handler: apiRoutes.Handler, Name: frontendServerIdentity, GetOnly: true, } diff --git a/frontend/ghost/ghost.go b/frontend/ghost/ghost.go deleted file mode 100644 index a8cb003..0000000 --- a/frontend/ghost/ghost.go +++ /dev/null @@ -1,10 +0,0 @@ -package ghost - -//go:generate $GOPATH/bin/easyjson -pkg -no_std_marshalers - -// Client is the ghost backend client -type Client interface { - GetPosts(params ...QueryParam) (posts *Posts, err error) - GetPostBySlug(slug string, params ...QueryParam) (posts *Posts, err error) - GetPageBySlug(slug string) (pages *Pages, err error) -} diff --git a/frontend/ghost/params.go b/frontend/ghost/params.go deleted file mode 100644 index 4da0076..0000000 --- a/frontend/ghost/params.go +++ /dev/null @@ -1,48 +0,0 @@ -package ghost - -import ( - "strconv" - - "github.com/valyala/fasthttp" -) - -// QueryParam is the generic query param applier -type QueryParam interface { - Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args) -} - -// QueryLimit returns limit param query -func QueryLimit(limit int) queryLimit { - return queryLimit{limit: limit} -} - -// QueryPage returns page param query -func QueryPage(page int) queryPage { - return queryPage{page: page} -} - -// queryLimit implements the limit param query applier -type queryLimit struct{ limit int } - -// Apply applies the limit argument to the query -func (ql queryLimit) Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args) { - - if ql.limit == 0 { - return - } - - args.Add("limit", strconv.Itoa(ql.limit)) -} - -// queryPage implements the page param query applier -type queryPage struct{ page int } - -// Apply applies the page argument to the query -func (qp queryPage) Apply(headers *fasthttp.RequestHeader, args *fasthttp.Args) { - - if qp.page < 2 { - return - } - - args.Add("page", strconv.Itoa(qp.page)) -} diff --git a/nginx/nginx.conf b/nginx/nginx.conf index c1c02c7..561ccf2 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -38,6 +38,10 @@ http { try_files $uri $uri/ @frontend; } + location = / { + proxy_pass http://frontend; + } + location @frontend { proxy_pass http://frontend; } diff --git a/frontend/config/config.go b/pkg/config/config.go similarity index 66% rename from frontend/config/config.go rename to pkg/config/config.go index 59a9949..68f1f8d 100644 --- a/frontend/config/config.go +++ b/pkg/config/config.go @@ -8,12 +8,19 @@ import ( "github.com/spf13/viper" ) +// Backend contains backend connection-specific configuration +type Backend struct { + Addr string `mapstructure:"addr"` + Secured bool `mapstructure:"secured"` + Headers map[string]string `mapstructure:"headers"` +} + // Content contains content-specific configuration type Content struct { - Backend string `mapstructure:"backend"` - Key string `mapstructure:"key"` - Pinned string `mapstructure:"pinned"` - PostsPerPage int `mapstructure:"postsPerPage"` + Backend Backend `mapstructure:"backend"` + Key string `mapstructure:"key"` + Pinned string `mapstructure:"pinned"` + PostsPerPage int `mapstructure:"postsPerPage"` } // Config contains application configuration @@ -36,7 +43,9 @@ func init() { pflag.String("unix", "", "unix socket path to listen") pflag.String("base", "", "http URI prefix") - pflag.String("content.backend", "demo.ghost.io:443", "ghost backend addr") + pflag.StringToString("content.backend.headers", nil, "map of additional headers to send") + pflag.String("content.backend.addr", "demo.ghost.io:443", "ghost backend addr") + pflag.Bool("content.backend.secured", true, "is ghost backend secured") pflag.String("content.key", "22444f78447824223cefc48062", "ghost content api key") pflag.String("content.pinned", "contact", "pinned page slug") pflag.Int("content.postsPerPage", 5, "amount of posts per page") diff --git a/frontend/content/blog.go b/pkg/content/blog.go similarity index 76% rename from frontend/content/blog.go rename to pkg/content/blog.go index ee325a7..441adf9 100644 --- a/frontend/content/blog.go +++ b/pkg/content/blog.go @@ -3,15 +3,15 @@ package content import ( "fmt" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data" ) // Blog content data type Blog struct { _ interface{} `template:"blog.go.tmpl"` - ghost.Meta - Pinned []ghost.Post - Posts []ghost.Post + data.Meta + Pinned []data.Post + Posts []data.Post } // Title returns blog content title diff --git a/frontend/content/error.go b/pkg/content/error.go similarity index 100% rename from frontend/content/error.go rename to pkg/content/error.go diff --git a/frontend/content/index.go b/pkg/content/index.go similarity index 75% rename from frontend/content/index.go rename to pkg/content/index.go index ed64707..12688d1 100644 --- a/frontend/content/index.go +++ b/pkg/content/index.go @@ -1,15 +1,13 @@ package content -import ( - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" -) +import "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data" // Index content data type Index struct { _ interface{} `template:"index.go.tmpl"` - ghost.Meta - Pinned []ghost.Post - Posts []ghost.Post + data.Meta + Pinned []data.Post + Posts []data.Post } // Title returns index title diff --git a/frontend/ghost/data.go b/pkg/ghost/data/data.go similarity index 92% rename from frontend/ghost/data.go rename to pkg/ghost/data/data.go index 87808b5..ec55ec6 100644 --- a/frontend/ghost/data.go +++ b/pkg/ghost/data/data.go @@ -1,4 +1,6 @@ -package ghost +package data + +//go:generate $GOPATH/bin/easyjson -pkg -no_std_marshalers import "html/template" diff --git a/frontend/ghost/ghost_easyjson.go b/pkg/ghost/data/data_easyjson.go similarity index 78% rename from frontend/ghost/ghost_easyjson.go rename to pkg/ghost/data/data_easyjson.go index 5faa3bc..8bd5108 100644 --- a/frontend/ghost/ghost_easyjson.go +++ b/pkg/ghost/data/data_easyjson.go @@ -1,6 +1,6 @@ // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT. -package ghost +package data import ( json "encoding/json" @@ -18,7 +18,7 @@ var ( _ easyjson.Marshaler ) -func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(in *jlexer.Lexer, out *Posts) { +func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(in *jlexer.Lexer, out *Posts) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -72,7 +72,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(in in.Consumed() } } -func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(out *jwriter.Writer, in Posts) { +func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(out *jwriter.Writer, in Posts) { out.RawByte('{') first := true _ = first @@ -102,14 +102,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(out // MarshalEasyJSON supports easyjson.Marshaler interface func (v Posts) MarshalEasyJSON(w *jwriter.Writer) { - easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(w, v) + easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(w, v) } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Posts) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost(l, v) + easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData(l, v) } -func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(in *jlexer.Lexer, out *Post) { +func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(in *jlexer.Lexer, out *Post) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -148,7 +148,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(in in.Consumed() } } -func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(out *jwriter.Writer, in Post) { +func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(out *jwriter.Writer, in Post) { out.RawByte('{') first := true _ = first @@ -182,14 +182,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(ou // MarshalEasyJSON supports easyjson.Marshaler interface func (v Post) MarshalEasyJSON(w *jwriter.Writer) { - easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(w, v) + easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(w, v) } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Post) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost1(l, v) + easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData1(l, v) } -func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(in *jlexer.Lexer, out *Pagination) { +func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(in *jlexer.Lexer, out *Pagination) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -226,7 +226,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(in in.Consumed() } } -func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(out *jwriter.Writer, in Pagination) { +func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(out *jwriter.Writer, in Pagination) { out.RawByte('{') first := true _ = first @@ -255,14 +255,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(ou // MarshalEasyJSON supports easyjson.Marshaler interface func (v Pagination) MarshalEasyJSON(w *jwriter.Writer) { - easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(w, v) + easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(w, v) } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Pagination) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost2(l, v) + easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData2(l, v) } -func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(in *jlexer.Lexer, out *Pages) { +func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(in *jlexer.Lexer, out *Pages) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -316,7 +316,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(in in.Consumed() } } -func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(out *jwriter.Writer, in Pages) { +func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(out *jwriter.Writer, in Pages) { out.RawByte('{') first := true _ = first @@ -346,14 +346,14 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(ou // MarshalEasyJSON supports easyjson.Marshaler interface func (v Pages) MarshalEasyJSON(w *jwriter.Writer) { - easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(w, v) + easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(w, v) } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Pages) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost3(l, v) + easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData3(l, v) } -func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(in *jlexer.Lexer, out *Meta) { +func easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(in *jlexer.Lexer, out *Meta) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -384,7 +384,7 @@ func easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(in in.Consumed() } } -func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(out *jwriter.Writer, in Meta) { +func easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(out *jwriter.Writer, in Meta) { out.RawByte('{') first := true _ = first @@ -398,10 +398,10 @@ func easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(ou // MarshalEasyJSON supports easyjson.Marshaler interface func (v Meta) MarshalEasyJSON(w *jwriter.Writer) { - easyjson72852e1bEncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(w, v) + easyjson794297d0EncodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(w, v) } // UnmarshalEasyJSON supports easyjson.Unmarshaler interface func (v *Meta) UnmarshalEasyJSON(l *jlexer.Lexer) { - easyjson72852e1bDecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhost4(l, v) + easyjson794297d0DecodeCodeTokarchUkMainnikaNikitaTokarchUkFrontendGhostData4(l, v) } diff --git a/pkg/ghost/ghost.go b/pkg/ghost/ghost.go new file mode 100644 index 0000000..84195d6 --- /dev/null +++ b/pkg/ghost/ghost.go @@ -0,0 +1,16 @@ +package ghost + +import ( + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params" +) + +// Client is the ghost backend client +type Client interface { + // GetPosts returns blog posts according to query params + GetPosts(queryParams ...params.Modifier) (posts *data.Posts, err error) + // GetPostBySlug returns a single post by its slug title and query params + GetPostBySlug(slug string, queryParams ...params.Modifier) (posts *data.Posts, err error) + // GetPageBySlug returns a single page by its slug title and query params + GetPageBySlug(slug string, queryParams ...params.Modifier) (pages *data.Pages, err error) +} diff --git a/pkg/ghost/params/params.go b/pkg/ghost/params/params.go new file mode 100644 index 0000000..ffb9994 --- /dev/null +++ b/pkg/ghost/params/params.go @@ -0,0 +1,39 @@ +package params + +// Params are generics query argument +type Params struct { + Limit int + Page int +} + +// Modifier function takes params and makes some changes +type Modifier func(params Params) Params + +// Modifiers is a list of modifier +type Modifiers []Modifier + +// Apply function modifies params +func (ms Modifiers) Apply(params Params) Params { + + for _, m := range ms { + params = m(params) + } + + return params +} + +// WithLimit modifier setups the limit +func WithLimit(limit int) Modifier { + return func(params Params) Params { + params.Limit = limit + return params + } +} + +// WithPage modifier setups the page +func WithPage(page int) Modifier { + return func(params Params) Params { + params.Page = page + return params + } +} diff --git a/frontend/ghost/client.go b/pkg/ghost/v4api/httpclient/client.go similarity index 50% rename from frontend/ghost/client.go rename to pkg/ghost/v4api/httpclient/client.go index e9c089e..a175854 100644 --- a/frontend/ghost/client.go +++ b/pkg/ghost/v4api/httpclient/client.go @@ -1,15 +1,20 @@ -package ghost +package httpclient import ( "fmt" + "strconv" "sync" "time" "github.com/mailru/easyjson" "github.com/valyala/fasthttp" + + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params" ) -var _ Client = (*HTTPClient)(nil) +var _ ghost.Client = (*HTTPClient)(nil) // Ghost content data URIs: const ( @@ -25,6 +30,7 @@ type HTTPClient struct { ContentKey string Addr string Secured bool + Headers map[string]string client *fasthttp.HostClient @@ -44,7 +50,7 @@ func (g *HTTPClient) setupClient() { } // doQuery does the method and unmarshals the result into the easyjson Unmarshaler -func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...QueryParam) (err error) { +func (g *HTTPClient) doQuery(path string, v easyjson.Unmarshaler, params params.Params) (err error) { g.setupClientOnce.Do(g.setupClient) @@ -55,17 +61,8 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu fasthttp.ReleaseRequest(req) }() - uri := req.URI() - uri.SetHost(g.Addr) - uri.SetPath(method) - uri.QueryArgs().Add("key", g.ContentKey) - if g.client.IsTLS { - uri.SetScheme("https") - } - - for _, param := range params { - param.Apply(&req.Header, uri.QueryArgs()) - } + g.setupRequest(path, req) + g.applyParams(params, req) err = g.client.DoTimeout(req, res, g.QueryTimeout) if err != nil { @@ -78,7 +75,6 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu resBytes := res.Body() if resBytes == nil && v == nil { return fmt.Errorf("nothing to unmarshal") - } if resBytes == nil { return @@ -89,13 +85,53 @@ func (g *HTTPClient) doQuery(method string, v easyjson.Unmarshaler, params ...Qu return } +// setupRequest does the necessary initial configuration to the http request +func (g *HTTPClient) setupRequest(path string, req *fasthttp.Request) { + + uri := req.URI() + + scheme := "http" + if g.Secured { + scheme = "https" + } + + uri.SetHost(g.Addr) + uri.SetPath(path) + uri.SetScheme(scheme) + + uri.QueryArgs().Add("key", g.ContentKey) + + for hKey, hValue := range g.Headers { + req.Header.Add(hKey, hValue) + } +} + +// applyParams function additionally configure the http request using params +func (g *HTTPClient) applyParams(p params.Params, req *fasthttp.Request) (err error) { + + uri := req.URI() + + limit := p.Limit + if limit > 0 { + uri.QueryArgs().Add("limit", strconv.Itoa(limit)) + } + + page := p.Page + if page > 1 { + uri.QueryArgs().Add("page", strconv.Itoa(page)) + } + + return +} + // GetPageBySlug returns the only one page using slug filter -func (g *HTTPClient) GetPageBySlug(slug string) (pages *Pages, err error) { +func (g *HTTPClient) GetPageBySlug(slug string, queryModifiers ...params.Modifier) (pages *data.Pages, err error) { - pages = &Pages{} + pages = &data.Pages{} + defaultParams := params.Params{} method := fmt.Sprintf(ghostAPIGetPageBySlug, slug) - err = g.doQuery(method, pages) + err = g.doQuery(method, pages, defaultParams) if err != nil { pages = nil } @@ -104,10 +140,13 @@ func (g *HTTPClient) GetPageBySlug(slug string) (pages *Pages, err error) { } // GetPosts returns posts -func (g *HTTPClient) GetPosts(params ...QueryParam) (posts *Posts, err error) { +func (g *HTTPClient) GetPosts(queryModifiers ...params.Modifier) (posts *data.Posts, err error) { + + posts = &data.Posts{} + defaultParams := params.Params{} + combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams) - posts = &Posts{} - err = g.doQuery(ghostAPIGetPosts, posts, params...) + err = g.doQuery(ghostAPIGetPosts, posts, combinedParams) if err != nil { posts = nil } @@ -116,12 +155,14 @@ func (g *HTTPClient) GetPosts(params ...QueryParam) (posts *Posts, err error) { } // GetPostBySlug returns the only one post using slug filter -func (g *HTTPClient) GetPostBySlug(slug string, params ...QueryParam) (posts *Posts, err error) { +func (g *HTTPClient) GetPostBySlug(slug string, queryModifiers ...params.Modifier) (posts *data.Posts, err error) { - posts = &Posts{} + posts = &data.Posts{} + defaultParams := params.Params{} + combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams) method := fmt.Sprintf(ghostAPIGetPostBySlug, slug) - err = g.doQuery(method, posts, params...) + err = g.doQuery(method, posts, combinedParams) if err != nil { posts = nil } diff --git a/frontend/renderer/blog.go b/pkg/routes/blog.go similarity index 53% rename from frontend/renderer/blog.go rename to pkg/routes/blog.go index f2d417d..dd26a2a 100644 --- a/frontend/renderer/blog.go +++ b/pkg/routes/blog.go @@ -1,18 +1,22 @@ -package renderer +package routes import ( - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" routing "github.com/jackwhelpton/fasthttp-routing/v2" + + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params" ) // blog handler renders blog data -func (r *Renderer) blog(c *routing.Context) (err error) { +func (r *Routes) blog(c *routing.Context) (err error) { postsPerPage := r.ContentConfig.PostsPerPage currentPage := c.QueryArgs().GetUintOrZero("page") - latestPosts, err := r.GhostClient.GetPosts(ghost.QueryLimit(postsPerPage), ghost.QueryPage(currentPage)) + latestPosts, err := r.GhostClient.GetPosts( + params.WithLimit(postsPerPage), + params.WithPage(currentPage), + ) if err != nil { return } diff --git a/frontend/renderer/error.go b/pkg/routes/error.go similarity index 78% rename from frontend/renderer/error.go rename to pkg/routes/error.go index 651b57a..57297e2 100644 --- a/frontend/renderer/error.go +++ b/pkg/routes/error.go @@ -1,16 +1,17 @@ -package renderer +package routes import ( "fmt" "net/http" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content" routing "github.com/jackwhelpton/fasthttp-routing/v2" "github.com/sirupsen/logrus" + + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content" ) // errorNotFound renders http error-404 template -func (r *Renderer) errorNotFound(c *routing.Context) (err error) { +func (r *Routes) errorNotFound(c *routing.Context) (err error) { errorContent := content.Error{Message: "not found"} @@ -18,7 +19,7 @@ func (r *Renderer) errorNotFound(c *routing.Context) (err error) { } // useErrorHandler is the middleware that catch handlers errors and render error template -func (r *Renderer) useErrorHandler(c *routing.Context) (err error) { +func (r *Routes) useErrorHandler(c *routing.Context) (err error) { worker := func() (err error) { diff --git a/frontend/renderer/index.go b/pkg/routes/index.go similarity index 61% rename from frontend/renderer/index.go rename to pkg/routes/index.go index 3de7767..c3f654b 100644 --- a/frontend/renderer/index.go +++ b/pkg/routes/index.go @@ -1,16 +1,17 @@ -package renderer +package routes import ( "net/http" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/content" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates" routing "github.com/jackwhelpton/fasthttp-routing/v2" + + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/content" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates" ) // rootRedirect redirects the root url to the index using http redirect -func (r *Renderer) rootRedirect(c *routing.Context) (err error) { +func (r *Routes) rootRedirect(c *routing.Context) (err error) { c.Redirect(templates.URLIndex, http.StatusFound) @@ -18,7 +19,7 @@ func (r *Renderer) rootRedirect(c *routing.Context) (err error) { } // index handler renders index data -func (r *Renderer) index(c *routing.Context) (err error) { +func (r *Routes) index(c *routing.Context) (err error) { pinnedPageSlug := r.ContentConfig.Pinned postsPerPage := r.ContentConfig.PostsPerPage @@ -28,7 +29,7 @@ func (r *Renderer) index(c *routing.Context) (err error) { return } - latestPosts, err := r.GhostClient.GetPosts(ghost.QueryLimit(postsPerPage)) + latestPosts, err := r.GhostClient.GetPosts(params.WithLimit(postsPerPage)) if err != nil { return } diff --git a/frontend/renderer/output.go b/pkg/routes/output.go similarity index 85% rename from frontend/renderer/output.go rename to pkg/routes/output.go index d9caa33..4e61b25 100644 --- a/frontend/renderer/output.go +++ b/pkg/routes/output.go @@ -1,11 +1,12 @@ -package renderer +package routes import ( "io" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates" routing "github.com/jackwhelpton/fasthttp-routing/v2" "github.com/valyala/fasthttp" + + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates" ) var _ routing.DataWriter = (*TemplateWriter)(nil) @@ -30,7 +31,7 @@ func (tw *TemplateWriter) Write(w io.Writer, content interface{}) error { } // useTemplateWriter is the routing middleware to set the default data writer -func (r *Renderer) useTemplateWriter(c *routing.Context) (err error) { +func (r *Routes) useTemplateWriter(c *routing.Context) (err error) { c.SetDataWriter(staticWriter) diff --git a/frontend/renderer/renderer.go b/pkg/routes/routes.go similarity index 66% rename from frontend/renderer/renderer.go rename to pkg/routes/routes.go index d21fce9..f2a8a3b 100644 --- a/frontend/renderer/renderer.go +++ b/pkg/routes/routes.go @@ -1,4 +1,4 @@ -package renderer +package routes import ( "sync" @@ -6,13 +6,13 @@ import ( routing "github.com/jackwhelpton/fasthttp-routing/v2" "github.com/valyala/fasthttp" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/config" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/ghost" - "code.tokarch.uk/mainnika/nikita-tokarch-uk/frontend/templates" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/config" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost" + "code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/templates" ) -// Renderer is the main handler that contains all routes handlers -type Renderer struct { +// Routes is the main handler that contains all routes handlers +type Routes struct { GhostClient ghost.Client ContentConfig config.Content @@ -25,13 +25,13 @@ type Renderer struct { } // Handler invokes the lazy once-initializer and then does the request -func (r *Renderer) Handler(ctx *fasthttp.RequestCtx) { +func (r *Routes) Handler(ctx *fasthttp.RequestCtx) { r.initOnce.Do(r.init) r.handler(ctx) } // init has the renderer initialization -func (r *Renderer) init() { +func (r *Routes) init() { router := routing.New() diff --git a/frontend/templates/blog.go.tmpl b/pkg/templates/blog.go.tmpl similarity index 100% rename from frontend/templates/blog.go.tmpl rename to pkg/templates/blog.go.tmpl diff --git a/frontend/templates/error.go.tmpl b/pkg/templates/error.go.tmpl similarity index 100% rename from frontend/templates/error.go.tmpl rename to pkg/templates/error.go.tmpl diff --git a/frontend/templates/funcs.go b/pkg/templates/funcs.go similarity index 85% rename from frontend/templates/funcs.go rename to pkg/templates/funcs.go index 7320b38..aedbf17 100644 --- a/frontend/templates/funcs.go +++ b/pkg/templates/funcs.go @@ -2,6 +2,7 @@ package templates import "html/template" +// UseFuncs returns a func map with template helpers functions func UseFuncs() template.FuncMap { return template.FuncMap{ "add": func(i int) int { diff --git a/frontend/templates/head.go.tmpl b/pkg/templates/head.go.tmpl similarity index 100% rename from frontend/templates/head.go.tmpl rename to pkg/templates/head.go.tmpl diff --git a/frontend/templates/index.go.tmpl b/pkg/templates/index.go.tmpl similarity index 100% rename from frontend/templates/index.go.tmpl rename to pkg/templates/index.go.tmpl diff --git a/frontend/templates/menu.go.tmpl b/pkg/templates/menu.go.tmpl similarity index 100% rename from frontend/templates/menu.go.tmpl rename to pkg/templates/menu.go.tmpl diff --git a/frontend/templates/post.go.tmpl b/pkg/templates/post.go.tmpl similarity index 100% rename from frontend/templates/post.go.tmpl rename to pkg/templates/post.go.tmpl diff --git a/frontend/templates/templates.go b/pkg/templates/templates.go similarity index 100% rename from frontend/templates/templates.go rename to pkg/templates/templates.go diff --git a/frontend/templates/urls.go b/pkg/templates/urls.go similarity index 100% rename from frontend/templates/urls.go rename to pkg/templates/urls.go