finish up translations and setup doc server stuff
This commit is contained in:
parent
ac307de76c
commit
5fb3c03e40
@ -6,7 +6,7 @@ api.elf: $(GOSRCS)
|
|||||||
go build -o $@
|
go build -o $@
|
||||||
|
|
||||||
run:
|
run:
|
||||||
API_DEBUG=true API_FRONTEND_URL=http://localhost:5173/ API_PASSWORD=test ./api.elf
|
API_DEBUG=true API_APP_URL=http://localhost:5173/ API_PASSWORD=test ./api.elf
|
||||||
|
|
||||||
format:
|
format:
|
||||||
gofmt -s -w .
|
gofmt -s -w .
|
||||||
|
@ -38,10 +38,10 @@ func (c *Type) Load() (err error) {
|
|||||||
// default options
|
// default options
|
||||||
c.Options = []Option{
|
c.Options = []Option{
|
||||||
{Name: "debug", Value: "false", Type: OPTION_TYPE_BOOL, Required: true}, // should display debug messgaes?
|
{Name: "debug", Value: "false", Type: OPTION_TYPE_BOOL, Required: true}, // should display debug messgaes?
|
||||||
{Name: "index", Value: "true", Type: OPTION_TYPE_BOOL, Required: false}, // should display the index page (view/index.md)?
|
|
||||||
|
|
||||||
{Name: "api_url", Value: "http://localhost:7001/", Type: OPTION_TYPE_URL, Required: true}, // API URL for the website
|
{Name: "url", Value: "http://localhost:7001/", Type: OPTION_TYPE_URL, Required: true}, // API URL for the website
|
||||||
{Name: "frontend_url", Value: "http://localhost:5173/", Type: OPTION_TYPE_URL, Required: true}, // frontend application URL for the website
|
{Name: "app_url", Value: "http://localhost:7002/", Type: OPTION_TYPE_URL, Required: true}, // frontend application URL for the website
|
||||||
|
{Name: "doc_url", Value: "http://localhost:7003/", Type: OPTION_TYPE_URL, Required: true}, // documentation URL for the website
|
||||||
|
|
||||||
{Name: "password", Value: "", Type: OPTION_TYPE_STR, Required: true}, // admin password
|
{Name: "password", Value: "", Type: OPTION_TYPE_STR, Required: true}, // admin password
|
||||||
{Name: "host", Value: "0.0.0.0:7001", Type: OPTION_TYPE_STR, Required: true}, // host the server should listen on
|
{Name: "host", Value: "0.0.0.0:7001", Type: OPTION_TYPE_STR, Required: true}, // host the server should listen on
|
||||||
|
@ -5,7 +5,6 @@ go 1.21.3
|
|||||||
require (
|
require (
|
||||||
github.com/gofiber/fiber/v2 v2.52.5
|
github.com/gofiber/fiber/v2 v2.52.5
|
||||||
github.com/mattn/go-sqlite3 v1.14.24
|
github.com/mattn/go-sqlite3 v1.14.24
|
||||||
github.com/russross/blackfriday/v2 v2.1.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -17,8 +17,6 @@ github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBW
|
|||||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||||
|
@ -3,30 +3,11 @@ package routes
|
|||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/ngn13/website/api/config"
|
"github.com/ngn13/website/api/config"
|
||||||
"github.com/ngn13/website/api/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GET_Index(c *fiber.Ctx) error {
|
func GET_Index(c *fiber.Ctx) error {
|
||||||
var (
|
|
||||||
md []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
conf := c.Locals("config").(*config.Type)
|
conf := c.Locals("config").(*config.Type)
|
||||||
|
doc := conf.GetURL("doc_url")
|
||||||
|
|
||||||
if !conf.GetBool("index") {
|
return c.Redirect(doc.JoinPath("/api").String())
|
||||||
return util.ErrNotFound(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
frontend := conf.GetURL("frontend_url")
|
|
||||||
api := conf.GetURL("api_url")
|
|
||||||
|
|
||||||
if md, err = util.Render("views/index.md", fiber.Map{
|
|
||||||
"frontend": frontend,
|
|
||||||
"api": api,
|
|
||||||
}); err != nil {
|
|
||||||
return util.ErrInternal(c, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.Markdown(c, md)
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func GET_News(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
db := c.Locals("database").(*database.Type)
|
db := c.Locals("database").(*database.Type)
|
||||||
conf := c.Locals("config").(*config.Type)
|
conf := c.Locals("config").(*config.Type)
|
||||||
frontend := conf.GetURL("frontend_url")
|
app := conf.GetURL("app_url")
|
||||||
lang := c.Params("lang")
|
lang := c.Params("lang")
|
||||||
|
|
||||||
if lang == "" || len(lang) != 2 {
|
if lang == "" || len(lang) != 2 {
|
||||||
@ -63,14 +63,16 @@ func GET_News(c *fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if feed, err = util.Render("views/news.xml", fiber.Map{
|
if feed, err = util.Render("views/news.xml", fiber.Map{
|
||||||
"frontend": frontend,
|
"updated": time.Now().Format(time.RFC3339),
|
||||||
"updated": time.Now().Format(time.RFC3339),
|
"entries": entries,
|
||||||
"entries": entries,
|
"lang": lang,
|
||||||
"lang": lang,
|
"app": app,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return util.ErrInternal(c, err)
|
return util.ErrInternal(c, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Set("Content-Disposition", "attachment; filename=\"news.atom\"")
|
||||||
c.Set("Content-Type", "application/atom+xml; charset=utf-8")
|
c.Set("Content-Type", "application/atom+xml; charset=utf-8")
|
||||||
|
|
||||||
return c.Send(feed)
|
return c.Send(feed)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/ngn13/website/api/config"
|
"github.com/ngn13/website/api/config"
|
||||||
"github.com/russross/blackfriday/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func IP(c *fiber.Ctx) string {
|
func IP(c *fiber.Ctx) string {
|
||||||
@ -20,15 +19,6 @@ func IP(c *fiber.Ctx) string {
|
|||||||
return c.IP()
|
return c.IP()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Markdown(c *fiber.Ctx, raw []byte) error {
|
|
||||||
exts := blackfriday.FencedCode
|
|
||||||
exts |= blackfriday.NoEmptyLineBeforeBlock
|
|
||||||
exts |= blackfriday.HardLineBreak
|
|
||||||
|
|
||||||
c.Set("Content-Type", "text/html; charset=utf-8")
|
|
||||||
return c.Send(blackfriday.Run(raw, blackfriday.WithExtensions(exts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func JSON(c *fiber.Ctx, code int, data fiber.Map) error {
|
func JSON(c *fiber.Ctx, code int, data fiber.Map) error {
|
||||||
if data == nil {
|
if data == nil {
|
||||||
data = fiber.Map{}
|
data = fiber.Map{}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">
|
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">
|
||||||
<title>{{.frontend.Host}} news</title>
|
<title>{{.app.Host}} news</title>
|
||||||
<updated>{{.updated}}</updated>
|
<updated>{{.updated}}</updated>
|
||||||
<subtitle>News and updates about my projects and self-hosted services</subtitle>
|
<subtitle>News and updates about my projects and self-hosted services</subtitle>
|
||||||
<link href="{{.frontend.JoinPath "/news"}}"></link>
|
<link href="{{.app.JoinPath "/news"}}"></link>
|
||||||
{{ range .entries }}
|
{{ range .entries }}
|
||||||
<entry>
|
<entry>
|
||||||
<title>{{.Title}}</title>
|
<title>{{.Title}}</title>
|
||||||
|
17
app/package-lock.json
generated
17
app/package-lock.json
generated
@ -1,16 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "website",
|
"name": "website",
|
||||||
"version": "5.0.0",
|
"version": "6.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "website",
|
"name": "website",
|
||||||
"version": "5.0.0",
|
"version": "6.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/dompurify": "^3.2.0",
|
"@types/dompurify": "^3.2.0",
|
||||||
"dompurify": "^3.2.3",
|
|
||||||
"marked": "^15.0.4",
|
|
||||||
"svelte-i18n": "^4.0.1"
|
"svelte-i18n": "^4.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -1398,17 +1396,6 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/marked": {
|
|
||||||
"version": "15.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.4.tgz",
|
|
||||||
"integrity": "sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw==",
|
|
||||||
"bin": {
|
|
||||||
"marked": "bin/marked.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/memoizee": {
|
"node_modules/memoizee": {
|
||||||
"version": "0.4.17",
|
"version": "0.4.17",
|
||||||
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz",
|
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"version": "6.0",
|
"version": "6.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "VITE_BUG_REPORT_URL=https://github.com/ngn13/website/issues VITE_API_URL=http://127.0.0.1:7001 VITE_FRONTEND_URL=http://localhost:5173 vite dev",
|
"dev": "vite --port 7002 dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview --host",
|
"preview": "vite preview --host",
|
||||||
"lint": "prettier --check .",
|
"lint": "prettier --check .",
|
||||||
@ -22,8 +22,6 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/dompurify": "^3.2.0",
|
"@types/dompurify": "^3.2.0",
|
||||||
"dompurify": "^3.2.3",
|
|
||||||
"marked": "^15.0.4",
|
|
||||||
"svelte-i18n": "^4.0.1"
|
"svelte-i18n": "^4.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { urljoin } from "$lib/util.js";
|
import { urljoin } from "$lib/util.js";
|
||||||
|
|
||||||
const version = "v1";
|
const version = "v1";
|
||||||
const url = urljoin(import.meta.env.VITE_API_URL, version);
|
const url = urljoin(import.meta.env.APP_API_URL, version);
|
||||||
|
|
||||||
function api_url(path = null, query = {}) {
|
function api_url(path = null, query = {}) {
|
||||||
return urljoin(url, path, query);
|
return urljoin(url, path, query);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{error}
|
{error}
|
||||||
{/if}
|
{/if}
|
||||||
</code>
|
</code>
|
||||||
<Link link={import.meta.env.VITE_BUG_REPORT_URL}>
|
<Link link={import.meta.env.APP_REPORT_URL}>
|
||||||
{$_("error.report")}
|
{$_("error.report")}
|
||||||
</Link>
|
</Link>
|
||||||
<img src="/profile/sad.png" alt="" />
|
<img src="/profile/sad.png" alt="" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import { color, date_from_ts } from "$lib/util.js";
|
import { urljoin, color, date_from_ts, language } from "$lib/util.js";
|
||||||
import { get_metrics } from "$lib/api.js";
|
import { get_metrics } from "$lib/api.js";
|
||||||
import Link from "$lib/link.svelte";
|
import Link from "$lib/link.svelte";
|
||||||
|
|
||||||
@ -17,15 +17,21 @@
|
|||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<span>
|
<span>
|
||||||
<Link href="/" bold={true}>{$_("footer.source")}</Link>
|
<Link link={import.meta.env.APP_SOURCE_URL} bold={true}>{$_("footer.source")}</Link>
|
||||||
</span>
|
</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>
|
<span>
|
||||||
<Link href="/" bold={true}>{$_("footer.license")}</Link>
|
<Link
|
||||||
|
link={urljoin(import.meta.env.APP_DOC_URL, "license", { lang: $language })}
|
||||||
|
bold={true}>{$_("footer.license")}</Link
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>
|
<span>
|
||||||
<Link href="/" bold={true}>{$_("footer.privacy")}</Link>
|
<Link
|
||||||
|
link={urljoin(import.meta.env.APP_DOC_URL, "privacy", { lang: $language })}
|
||||||
|
bold={true}>{$_("footer.privacy")}</Link
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span>
|
<span>
|
||||||
|
@ -2,20 +2,30 @@
|
|||||||
import { language, set_lang } from "$lib/util.js";
|
import { language, set_lang } from "$lib/util.js";
|
||||||
import languages from "$lib/lang.js";
|
import languages from "$lib/lang.js";
|
||||||
|
|
||||||
let icon = "",
|
let icon = null,
|
||||||
indx = 0,
|
indx = 0,
|
||||||
len = languages.length;
|
len = languages.length;
|
||||||
|
|
||||||
function next() {
|
function next_indx() {
|
||||||
if (indx >= languages.length) indx = 0;
|
if (indx + 1 >= len) return 0;
|
||||||
|
return indx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
icon = languages[indx].icon;
|
function next_lang(inc) {
|
||||||
set_lang(languages[indx++].code);
|
let new_indx = next_indx();
|
||||||
|
if (inc) indx = new_indx;
|
||||||
|
return languages[new_indx];
|
||||||
|
}
|
||||||
|
|
||||||
|
function next() {
|
||||||
|
set_lang(next_lang(true).code);
|
||||||
|
icon = next_lang(false).icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (indx = 0; indx < len; indx++) {
|
for (indx = 0; indx < len; indx++) {
|
||||||
if (languages[indx].code == $language) {
|
if (languages[indx].code == $language) {
|
||||||
icon = languages[indx++].icon;
|
set_lang(languages[indx].code);
|
||||||
|
icon = next_lang(false).icon;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,9 @@
|
|||||||
import { _ } from "svelte-i18n";
|
import { _ } from "svelte-i18n";
|
||||||
|
|
||||||
export let service = {};
|
export let service = {};
|
||||||
let style = "";
|
|
||||||
|
|
||||||
if (service.check_res == 0) style = "opacity: 70%";
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main {style}>
|
<main>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h1>{service.name}</h1>
|
<h1>{service.name}</h1>
|
||||||
@ -44,7 +41,7 @@
|
|||||||
{$_("services.status.up")}
|
{$_("services.status.up")}
|
||||||
</span>
|
</span>
|
||||||
{:else if service.check_res == 2}
|
{:else if service.check_res == 2}
|
||||||
<span style="background: var(--white-2)">
|
<span style="background: var(--{color()}); filter: brightness(50%);">
|
||||||
{$_("services.status.slow")}
|
{$_("services.status.slow")}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@ -70,6 +67,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
color: var(--white-1);
|
color: var(--white-1);
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
main .info .title h1 {
|
main .info .title h1 {
|
||||||
|
@ -49,13 +49,13 @@ function urljoin(url, path = null, query = {}) {
|
|||||||
else if (path[0] === "/") url = new URL(path.slice(1), url);
|
else if (path[0] === "/") url = new URL(path.slice(1), url);
|
||||||
else url = new URL(path, url);
|
else url = new URL(path, url);
|
||||||
|
|
||||||
for (let k in query) url.searchParams.append(query[k]);
|
for (let k in query) url.searchParams.append(k, query[k]);
|
||||||
|
|
||||||
return url.href;
|
return url.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
function frontend_url(path = null, query = {}) {
|
function frontend_url(path = null, query = {}) {
|
||||||
return urljoin(import.meta.env.VITE_FRONTEND_URL, path, query);
|
return urljoin(import.meta.env.APP_URL, path, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function color() {
|
function color() {
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
"navbar": {
|
"navbar": {
|
||||||
"home": "home",
|
"home": "home",
|
||||||
"services": "services",
|
"services": "services",
|
||||||
"news": "news",
|
|
||||||
"donate": "donate"
|
"donate": "donate"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
@ -10,7 +9,7 @@
|
|||||||
"welcome": {
|
"welcome": {
|
||||||
"title": "about",
|
"title": "about",
|
||||||
"desc": "Welcome to my website, I'm ngn",
|
"desc": "Welcome to my website, I'm ngn",
|
||||||
"whoami": "I'm a privacy, security and freedom addvocate high-schooler from Turkey",
|
"whoami": "I'm a security, privacy and freedom advocate high-schooler from Turkey",
|
||||||
"interest": "I'm interested in system security and software development",
|
"interest": "I'm interested in system security and software development",
|
||||||
"support": "I love and support Free/Libre and Open Source Software (FLOSS)"
|
"support": "I love and support Free/Libre and Open Source Software (FLOSS)"
|
||||||
},
|
},
|
||||||
@ -35,7 +34,7 @@
|
|||||||
"security": "All use SSL encrypted connection and they are all privacy-respecting",
|
"security": "All use SSL encrypted connection and they are all privacy-respecting",
|
||||||
"privacy": "Accessible from clearnet, TOR and I2P, no region or network blocks",
|
"privacy": "Accessible from clearnet, TOR and I2P, no region or network blocks",
|
||||||
"bullshit": "No CDNs, no cloudflare, no CAPTCHA, no analytics, no bullshit",
|
"bullshit": "No CDNs, no cloudflare, no CAPTCHA, no analytics, no bullshit",
|
||||||
"link": "Check them out!"
|
"link": "See all the services!"
|
||||||
},
|
},
|
||||||
"projects": {
|
"projects": {
|
||||||
"title": "projects",
|
"title": "projects",
|
||||||
@ -54,11 +53,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"donate": {
|
"donate": {
|
||||||
"title": "donate money!",
|
"title": "Donate Money!",
|
||||||
"info": "I spend a lot of time working on different projects and maintaining different services.",
|
"info": "I spend a lot of time and money on different projects and maintaining different services.",
|
||||||
"price": "I mostly pay for hosting and electricity. Which when added up costs around 550₺ per month, that is Turkish Lira, equals to ~$15 at time of writing (ik the economy is great).",
|
"price": "I mostly pay for hosting and electricity. Which when added up costs around 550₺ per month (~$15 at the time of writing).",
|
||||||
"details": "So even a small donation would be highly appreciated and it would help me keep everything up and running.",
|
"details": "So even a small donation would be useful. And it would help me keep everything up and running.",
|
||||||
"thanks": "Also huge thanks to all of you who has donated so far, as I said, I highly appreciate it. Thank you!",
|
"thanks": "Also huge thanks to all of you who have donated so far!",
|
||||||
"table": {
|
"table": {
|
||||||
"platform": "Platform",
|
"platform": "Platform",
|
||||||
"address": "Adress/Link"
|
"address": "Adress/Link"
|
||||||
@ -66,7 +65,7 @@
|
|||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"title": "Something went wrong!",
|
"title": "Something went wrong!",
|
||||||
"report": "report this issue"
|
"report": "Report this issue"
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"source": "Source",
|
"source": "Source",
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
{
|
{
|
||||||
"navbar": {
|
"navbar": {
|
||||||
"home": "anasayfa",
|
"home": "anasayfa",
|
||||||
"news": "haberler",
|
|
||||||
"services": "servisler",
|
"services": "servisler",
|
||||||
"language": "dil"
|
"donate": "bağış"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
|
"title": "Merhaba Dünya!",
|
||||||
"welcome": {
|
"welcome": {
|
||||||
"title": "Websiteme hoşgeldiniz, ben ngn",
|
"title": "hakkımda",
|
||||||
|
"desc": "Websiteme hoşgeldiniz, ben ngn",
|
||||||
"whoami": "Türkiye'den, güvenlik, gizlik ve özgürlük savunucusu bir liseliyim",
|
"whoami": "Türkiye'den, güvenlik, gizlik ve özgürlük savunucusu bir liseliyim",
|
||||||
"interest": "Sistem güvenliği ve yazılım geliştirmek ile ilgileniyorum",
|
"interest": "Sistem güvenliği ve yazılım geliştirmek ile ilgileniyorum",
|
||||||
"support": "Özgür/Libre ve Açık Kaynaklı Yazılımı (FLOSS) seviyorum ve destekliyorum"
|
"support": "Özgür/Libre ve Açık Kaynaklı Yazılımı (FLOSS) seviyorum ve destekliyorum"
|
||||||
},
|
},
|
||||||
"work": {
|
"work": {
|
||||||
"title": "Zamanım çoğunlukla şunlar ile geçiyor...",
|
"title": "iş",
|
||||||
|
"desc": "Şuan bir işim yok, o yüzden zamanımın çoğunu şunlarla geçiriyorum:",
|
||||||
"build": "salak şeyler inşa etmek",
|
"build": "salak şeyler inşa etmek",
|
||||||
"fix": "salak şeyleri düzeltmek",
|
"fix": "salak şeyleri düzeltmek",
|
||||||
"ctf": "CTF challenge'ları çözmek",
|
"ctf": "CTF challenge'ları çözmek",
|
||||||
@ -21,24 +23,56 @@
|
|||||||
"wiki": "wikimi genişletmek"
|
"wiki": "wikimi genişletmek"
|
||||||
},
|
},
|
||||||
"links": {
|
"links": {
|
||||||
"title": "Eğer benim ile iletişime geçmek istiyorsanız, işte bazı faydalı linkler",
|
"title": "iletişim",
|
||||||
"prefer": "tercihim"
|
"desc": "Eğer benim ile iletişime geçmek istiyorsanız, işte bazı faydalı linkler",
|
||||||
|
"prefer": "Email'i fazlasıyla tercih ediyorum, PGP anahtarım ile şifreli email'ler gönderebilirsiniz"
|
||||||
},
|
},
|
||||||
"info": {
|
"services": {
|
||||||
"title": "Salak şeyler inşa etmenin yanı sıra, herkes için kullanıma açık özgür ve ücretsiz servisler host ediyorum",
|
"title": "servisler",
|
||||||
|
"desc": "Salak şeyler inşa etmenin yanı sıra, herkes için kullanıma açık özgür ve ücretsiz servisler host ediyorum",
|
||||||
"speed": "Tüm servisler 600 Mbit/s ağ arayüzü üzerinden erişilebilir",
|
"speed": "Tüm servisler 600 Mbit/s ağ arayüzü üzerinden erişilebilir",
|
||||||
"security": "Hepsi SSL şifreli bağlantı kullanıyor ve hepsi gizliğinize saygı gösteriyor",
|
"security": "Hepsi SSL şifreli bağlantı kullanıyor ve hepsi gizliğinize saygı gösteriyor",
|
||||||
"privacy": "Accessible from clearnet, TOR and I2P, no region or network blocks",
|
"privacy": "Accessible from clearnet, TOR and I2P, no region or network blocks",
|
||||||
"privacy": "Açık ağdan, TOR ve I2P'den erişilebilirler, bölge ya da ağ blokları yok",
|
"privacy": "Açık ağdan, TOR ve I2P'den erişilebilirler, bölge ya da ağ blokları yok",
|
||||||
"bullshit": "CDN yok, cloudflare yok, CAPTCHA yok, analitikler yok, boktan saçmalıklar yok",
|
"bullshit": "CDN yok, cloudflare yok, CAPTCHA yok, analitikler yok, boktan saçmalıklar yok",
|
||||||
"link": "tüm servisleri incele"
|
"link": "Tüm servisleri incele!"
|
||||||
|
},
|
||||||
|
"projects": {
|
||||||
|
"title": "projeler",
|
||||||
|
"desc": "Çoğunlukla özgür yazılım projeleri üzerinde çalışıyorum, işte ilginç bulabileceğiniz bazı projelerim"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"services": {
|
||||||
|
"title": "Servis Durumu",
|
||||||
|
"search": "Bir servisi ara",
|
||||||
|
"feed": "Yenilikler ve güncellemeler",
|
||||||
|
"last": "Son kontrol zamanı {time}",
|
||||||
|
"status": {
|
||||||
|
"up": "Çalışıyor",
|
||||||
|
"down": "Kapalı",
|
||||||
|
"slow": "Yavaş"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"donate": {
|
||||||
|
"title": "Para Bağışla!",
|
||||||
|
"info": "Farklı projeler ve farklı servisleri yönetmek için oldukça zaman ve para harcıyorum.",
|
||||||
|
"price": "Çoğunlukla hosting ve elektrik için ödeme yapıyorum. Bunlar eklendiği zaman aylık 550₺ civarı bir miktar oluyor (yazdığım sırada ~15$).",
|
||||||
|
"details": "Bu sebepten küçük bir bağış bile oldukça faydalı olacaktır. Ve herşeyi açık ve çalışmakta tutmama yardımcı olacaktır.",
|
||||||
|
"thanks": "Ayrıca şuana kadar bağışta bulunan herkese çok teşekkür ederim!",
|
||||||
|
"table": {
|
||||||
|
"platform": "Platform",
|
||||||
|
"address": "Adres/Bağlantı"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"title": "Birşeyler yanlış gitti!",
|
||||||
|
"report": "Bu sorunu raporlayın"
|
||||||
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"source": "Kaynak",
|
"source": "Kaynak",
|
||||||
"license": "Lisans",
|
"license": "Lisans",
|
||||||
"privacy": "Gizlilik",
|
"privacy": "Gizlilik",
|
||||||
"powered": "Svelte, Go, SQLite ve yemek param tarafından destekleniyor",
|
"powered": "Svelte, Go, SQLite ve bağışlar tarafından destekleniyor",
|
||||||
"number": "{since} tarihinden beri {number}. ziyaretçisiniz",
|
"number": "{since} tarihinden beri {number}. ziyaretçisiniz",
|
||||||
"congrat": "tebrikler!!",
|
"congrat": "tebrikler!!",
|
||||||
"version": "Kullan API versiyonu {api_version}, arayüz versiyonu {frontend_version}"
|
"version": "Kullan API versiyonu {api_version}, arayüz versiyonu {frontend_version}"
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
</Card>
|
</Card>
|
||||||
<Card title={$_("home.services.title")}>
|
<Card title={$_("home.services.title")}>
|
||||||
<span>
|
<span>
|
||||||
{$_("home.services.desc")}
|
{$_("home.services.desc")}:
|
||||||
</span>
|
</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
@ -81,7 +81,9 @@
|
|||||||
{$_("home.projects.desc")}:
|
{$_("home.projects.desc")}:
|
||||||
</span>
|
</span>
|
||||||
<ul>
|
<ul>
|
||||||
{#each projects as project}
|
{#each projects.filter((p) => {
|
||||||
|
return p.desc[$language] !== "" && p.desc[$language] !== null && p.desc[$language] !== undefined;
|
||||||
|
}) as project}
|
||||||
<li>
|
<li>
|
||||||
<Link active={true} link={project.url}>{project.name}</Link>:
|
<Link active={true} link={project.url}>{project.name}</Link>:
|
||||||
{project.desc[$language]}
|
{project.desc[$language]}
|
||||||
|
@ -38,7 +38,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="services">
|
<div class="services">
|
||||||
{#each services as service}
|
{#each services.filter((s) => {
|
||||||
|
return s.desc[$language] !== "" && s.desc[$language] !== null && s.desc[$language] !== undefined;
|
||||||
|
}) as service}
|
||||||
<Service {service} />
|
<Service {service} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,12 +3,25 @@ import { defineConfig } from "vite";
|
|||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
|
|
||||||
|
const default_env = {
|
||||||
|
REPORT_URL: "https://github.com/ngn13/website/issues",
|
||||||
|
SOURCE_URL: "https://github.com/ngn13/website",
|
||||||
|
API_URL: "http://localhost:7001",
|
||||||
|
URL: "http://localhost:7002",
|
||||||
|
DOC_URL: "http://localhost:7003",
|
||||||
|
};
|
||||||
|
|
||||||
const file = fileURLToPath(new URL("package.json", import.meta.url));
|
const file = fileURLToPath(new URL("package.json", import.meta.url));
|
||||||
const json = readFileSync(file, "utf8");
|
const json = readFileSync(file, "utf8");
|
||||||
const pkg = JSON.parse(json);
|
const pkg = JSON.parse(json);
|
||||||
|
|
||||||
|
for (let env in default_env) {
|
||||||
|
if (process.env["APP_" + env] === undefined) process.env["APP_" + env] = default_env[env];
|
||||||
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit()],
|
||||||
|
envPrefix: "APP",
|
||||||
define: {
|
define: {
|
||||||
pkg: pkg,
|
pkg: pkg,
|
||||||
},
|
},
|
||||||
|
225
doc/.clang-format
Normal file
225
doc/.clang-format
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: true
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments:
|
||||||
|
Kind: Always
|
||||||
|
OverEmptyLines: 0
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
AttributeMacros:
|
||||||
|
- __capability
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: true
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakAfterAttributes: Never
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakArrays: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 120
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IfMacros:
|
||||||
|
- KJ_IF_MAYBE
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
SortPriority: 0
|
||||||
|
CaseSensitive: false
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IncludeIsMainSourceRegex: ''
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentExternBlock: AfterExternBlock
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: false
|
||||||
|
InsertNewlineAtEOF: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
IntegerLiteralSeparator:
|
||||||
|
Binary: 0
|
||||||
|
BinaryMinDigits: 0
|
||||||
|
Decimal: 0
|
||||||
|
DecimalMinDigits: 0
|
||||||
|
Hex: 0
|
||||||
|
HexMinDigits: 0
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
LineEnding: DeriveLF
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PackConstructorInitializers: BinPack
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakOpenParenthesis: 0
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyIndentedWhitespace: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
PPIndentWidth: -1
|
||||||
|
QualifierAlignment: Leave
|
||||||
|
ReferenceAlignment: Pointer
|
||||||
|
ReflowComments: true
|
||||||
|
RemoveBracesLLVM: false
|
||||||
|
RemoveSemicolon: false
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
RequiresExpressionIndentation: OuterScope
|
||||||
|
SeparateDefinitionBlocks: Leave
|
||||||
|
ShortNamespaceLines: 1
|
||||||
|
SortIncludes: false
|
||||||
|
SortJavaStaticImport: Before
|
||||||
|
SortUsingDeclarations: LexicographicNumeric
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceAroundPointerQualifiers: Default
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCaseColon: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: true
|
||||||
|
AfterForeachMacros: true
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterIfMacros: true
|
||||||
|
AfterOverloadedOperator: false
|
||||||
|
AfterRequiresInClause: false
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: Never
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: -1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Latest
|
||||||
|
StatementAttributeLikeMacros:
|
||||||
|
- Q_EMIT
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- STRINGIZE
|
||||||
|
...
|
||||||
|
|
4
doc/.gitignore
vendored
Normal file
4
doc/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
compile_commands.json
|
||||||
|
.cache
|
||||||
|
*.elf
|
||||||
|
dist
|
35
doc/Makefile
Normal file
35
doc/Makefile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# dirs
|
||||||
|
DIRS = $(shell find src/* -type d)
|
||||||
|
DISTDIR = dist
|
||||||
|
OUTDIRS = $(patsubst src/%,$(DISTDIR)/%,$(DIRS))
|
||||||
|
|
||||||
|
# sources
|
||||||
|
HSRCS = $(wildcard inc/*.h)
|
||||||
|
CSRCS = $(shell find -type f -name '*.c')
|
||||||
|
OBJS = $(patsubst ./src/%.c,./$(DISTDIR)/%.o,$(CSRCS))
|
||||||
|
|
||||||
|
# compiler flags
|
||||||
|
CFLAGS = -O3 -fstack-protector-strong -fcf-protection=full -fstack-clash-protection
|
||||||
|
LIBS = -lctorm -lcmark
|
||||||
|
INCLUDE = -I./inc
|
||||||
|
|
||||||
|
all: doc.elf
|
||||||
|
|
||||||
|
doc.elf: $(OBJS)
|
||||||
|
echo $(OBJS) $(OUTDIRS)
|
||||||
|
gcc $(CFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
$(DISTDIR)/%.o: src/%.c
|
||||||
|
@mkdir -pv $(OUTDIRS)
|
||||||
|
gcc $(CFLAGS) $(INCLUDE) -c -o $@ $^ $(LIBS)
|
||||||
|
|
||||||
|
format:
|
||||||
|
clang-format -i -style=file $(CSRCS) $(HSRCS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(DISTDIR)
|
||||||
|
|
||||||
|
run:
|
||||||
|
./doc.elf
|
||||||
|
|
||||||
|
.PHONY: format clean run
|
18
doc/inc/config.h
Normal file
18
doc/inc/config.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct option {
|
||||||
|
const char *name;
|
||||||
|
char *value;
|
||||||
|
bool required;
|
||||||
|
} option_t;
|
||||||
|
|
||||||
|
typedef struct config {
|
||||||
|
option_t *options;
|
||||||
|
int32_t count;
|
||||||
|
} config_t;
|
||||||
|
|
||||||
|
int32_t config_load(config_t *conf);
|
||||||
|
char *config_get(config_t *conf, const char *name);
|
4
doc/inc/routes.h
Normal file
4
doc/inc/routes.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <ctorm/all.h>
|
||||||
|
|
||||||
|
void GET_read(req_t *req, res_t *res);
|
39
doc/src/config.c
Normal file
39
doc/src/config.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include <ctorm/log.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
option_t options[] = {
|
||||||
|
{"host", "0.0.0.0:7003", true }, // host the server should listen on
|
||||||
|
{NULL, NULL, false},
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t config_load(config_t *conf) {
|
||||||
|
bzero(conf, sizeof(*conf));
|
||||||
|
|
||||||
|
char *value = NULL;
|
||||||
|
conf->options = options;
|
||||||
|
|
||||||
|
for (option_t *opt = conf->options; opt->name != NULL; opt++) {
|
||||||
|
if ((value = getenv(opt->name)) != NULL)
|
||||||
|
opt->value = value;
|
||||||
|
|
||||||
|
if (opt->required && *opt->value == 0) {
|
||||||
|
error("please specify a value for the required config option %s", opt->name);
|
||||||
|
errno = EFAULT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
conf->count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *config_get(config_t *conf, const char *name) {
|
||||||
|
for (int32_t i = 0; i < conf->count; i++)
|
||||||
|
if (strcmp(conf->options[i].name, name) == 0)
|
||||||
|
return conf->options[i].value;
|
||||||
|
return NULL;
|
||||||
|
}
|
25
doc/src/main.c
Normal file
25
doc/src/main.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <ctorm/all.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "routes.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
config_t conf;
|
||||||
|
app_config_t config;
|
||||||
|
|
||||||
|
if (config_load(&conf) < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
app_config_new(&config);
|
||||||
|
config.disable_logging = true;
|
||||||
|
|
||||||
|
app_t *app = app_new(&config);
|
||||||
|
GET(app, "/read", GET_read);
|
||||||
|
|
||||||
|
if (!app_run(app, config_get(&conf, "host")))
|
||||||
|
error("failed to start the app: %s", app_geterror());
|
||||||
|
|
||||||
|
app_free(app);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
118
doc/src/routes/read.c
Normal file
118
doc/src/routes/read.c
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#include <linux/limits.h>
|
||||||
|
#include <ctorm/all.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cmark.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "routes.h"
|
||||||
|
|
||||||
|
void GET_read(req_t *req, res_t *res) {
|
||||||
|
const char *lang = REQ_QUERY("lang");
|
||||||
|
const char *name = REQ_QUERY("name");
|
||||||
|
|
||||||
|
char fp[PATH_MAX + 1], md[NAME_MAX + 1];
|
||||||
|
struct dirent *dirent = NULL;
|
||||||
|
int32_t name_len = 0, ent_len = 0;
|
||||||
|
DIR *dir = NULL;
|
||||||
|
|
||||||
|
bzero(fp, sizeof(fp));
|
||||||
|
bzero(md, sizeof(md));
|
||||||
|
|
||||||
|
if (NULL == name)
|
||||||
|
return RES_REDIRECT("/");
|
||||||
|
|
||||||
|
name_len = strlen(name);
|
||||||
|
|
||||||
|
if (NULL == lang)
|
||||||
|
lang = "en";
|
||||||
|
|
||||||
|
if (NULL == (dir = opendir("docs"))) {
|
||||||
|
error("failed to open the docs dir: %s", strerror(errno));
|
||||||
|
RES_SENDFILE("html/internal.html");
|
||||||
|
res->code = 500;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dirent = readdir(dir)) != NULL) {
|
||||||
|
if (strncmp(dirent->d_name, lang, PATH_MAX) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
if (NULL == dirent) {
|
||||||
|
RES_SENDFILE("html/notfound.html");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(fp, sizeof(fp), "docs/%s", lang);
|
||||||
|
|
||||||
|
if (NULL == (dir = opendir(fp))) {
|
||||||
|
error("failed to open the language dir: %s", strerror(errno));
|
||||||
|
RES_SENDFILE("html/internal.html");
|
||||||
|
res->code = 500;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dirent = readdir(dir)) != NULL) {
|
||||||
|
if ((ent_len = strlen(dirent->d_name) - 3) != name_len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(dirent->d_name, name, name_len) == 0) {
|
||||||
|
memcpy(md, dirent->d_name, ent_len + 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
if (NULL == dirent) {
|
||||||
|
RES_SENDFILE("html/notfound.html");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *md_content = NULL, md_fp[PATH_MAX + 1];
|
||||||
|
struct stat md_st;
|
||||||
|
int md_fd = 0;
|
||||||
|
|
||||||
|
snprintf(md_fp, sizeof(fp), "%s/%s", fp, md);
|
||||||
|
|
||||||
|
if ((md_fd = open(md_fp, O_RDONLY)) < 0) {
|
||||||
|
error("failed to open %s: %s", fp, strerror(errno));
|
||||||
|
goto err_internal_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fstat(md_fd, &md_st) < 0) {
|
||||||
|
error("failed to fstat %s: %s", fp, strerror(errno));
|
||||||
|
goto err_internal_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((md_content = mmap(0, md_st.st_size, PROT_READ, MAP_PRIVATE, md_fd, 0)) == NULL) {
|
||||||
|
error("failed to mmap %s: %s", fp, strerror(errno));
|
||||||
|
goto err_internal_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *parsed = cmark_markdown_to_html(md_content, md_st.st_size, CMARK_OPT_DEFAULT);
|
||||||
|
RES_SEND(parsed);
|
||||||
|
|
||||||
|
free(parsed);
|
||||||
|
munmap(md_content, md_st.st_size);
|
||||||
|
close(md_fd);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_internal_close:
|
||||||
|
close(md_fd);
|
||||||
|
|
||||||
|
RES_SENDFILE("html/internal.html");
|
||||||
|
return;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user