1 Commits

Author SHA1 Message Date
71b7554d45 Update dependency marked to v15.0.9 2025-04-22 02:02:54 +00:00
37 changed files with 238 additions and 321 deletions

141
README.md
View File

@ -4,112 +4,85 @@
![](https://git.ngn.tf/ngn/website/actions/workflows/build-api.yml/badge.svg) ![](https://git.ngn.tf/ngn/website/actions/workflows/build-api.yml/badge.svg)
![](https://git.ngn.tf/ngn/website/actions/workflows/build-doc.yml/badge.svg) ![](https://git.ngn.tf/ngn/website/actions/workflows/build-doc.yml/badge.svg)
This repo contains all the source code for my personal website, This repo contains all the source code for my personal website, [ngn.tf](https://ngn.tf)
[ngn.tf](https://ngn.tf) All code is licensed under AGPL version 3 (see All code is licensed under AGPL version 3 (see [LICENSE.txt](LICENSE.txt))
[LICENSE.txt](LICENSE.txt))
## Directory structure ## Directory structure
### `app` ### `app`
Contains frontend application, written with SvelteKit. It supports full SSR. Contains frontend application, written with SvelteKit. It supports full SSR.
Contains modified CSS from Contains modified CSS from [github-markdown-css](https://github.com/sindresorhus/github-markdown-css)
[github-markdown-css](https://github.com/sindresorhus/github-markdown-css) and and fonts from [NerdFonts](https://www.nerdfonts.com/)
fonts from [NerdFonts](https://www.nerdfonts.com/)
### `api` ### `api`
Contains the API server, written in Go. It uses the [Fiber](https://github.com/gofiber/fiber) web
framework which offers an [Express](https://expressjs.com/) like experience. I choose Fiber since I've used
worked with express a lot in the past. However previously the I was using [Gin](https://github.com/gin-gonic/gin)
(see history section).
Contains the API server, written in Go. It uses the API stores all the data in a local SQLite(3) database. Go doesn't support SQLite3 out of the box so
[Fiber](https://github.com/gofiber/fiber) web framework which offers an I'm using [mattn's sqlite3 driver](https://github.com/mattn/go-sqlite3).
[Express](https://expressjs.com/) like experience. I choose Fiber since I've
used worked with express a lot in the past. However previously the I was using
[Gin](https://github.com/gin-gonic/gin) (see history section).
API stores all the data in a local SQLite(3) database. Go doesn't support
SQLite3 out of the box so I'm using
[mattn's sqlite3 driver](https://github.com/mattn/go-sqlite3).
### `doc` ### `doc`
Contains the documentation server, written in C. It uses the [ctorm](https://github.com/ngn13/ctorm) web
Contains the documentation server, written in C. It uses the framework, which is a framework that I myself wrote. Unlike the frontend application or the API server, it's not
[ctorm](https://github.com/ngn13/ctorm) web framework, which is a framework that accessable by public, the frontend application gets the documentation content from this server and renders it using
I myself wrote. Unlike the frontend application or the API server, it's not SSR. The reason I don't use the API for hosting the documentation content is that I want a separate server for hosting
accessable by public, the frontend application gets the documentation content
from this server and renders it using SSR. The reason I don't use the API for
hosting the documentation content is that I want a separate server for hosting
static content, API is only for hosting dynamic stuff. static content, API is only for hosting dynamic stuff.
### `admin` ### `admin`
The frontend application does not contain an admin interface, I do the administration stuff (such as adding news posts,
The frontend application does not contain an admin interface, I do the adding services etc.) using the python script in this directory. This script can be installed on to the PATH by running
administration stuff (such as adding news posts, adding services etc.) using the the Makefile install script. After installation it can be used by running `admin_script`.
python script in this directory. This script can be installed on to the PATH by
running the Makefile install script. After installation it can be used by
running `admin_script`.
## Deployment ## Deployment
Easiest way to deploy is to use docker. There is `compose.yml` and a `run.sh` script in the [deploy](deploy/) directory
Easiest way to deploy is to use docker. There is `compose.yml` and a `run.sh` that can be used to startup all the docker containers. Configuration options are passed during build time for the frontend
script in the [deploy](deploy/) directory that can be used to startup all the application, and for others it's passed with environment variables.
docker containers. Configuration options are passed during build time for the
frontend application, and for others it's passed with environment variables.
## History ## History
Some nostalgic history/changelog stuff (just for the major version numbers): Some nostalgic history/changelog stuff (just for the major version numbers):
- **v0.1 (late 2020 - early 2021)**: First ever version of my website, it was - **v0.1 (late 2020 - early 2021)**: First ever version of my website, it was just a simple HTML/CSS page,
just a simple HTML/CSS page, I never published any of the source code and I I never published any of the source code and I wiped the local copy on my USB drive in early 2022, I still
wiped the local copy on my USB drive in early 2022, I still remember what it remember what it looked like though, it looked like I made entire website in microsoft paint... while blindfoled,
looked like though, it looked like I made entire website in microsoft paint... so yeah it was shit.
while blindfoled, so yeah it was shit.
- **v1.0 (early 2021 - late 2022)**: This version was actualy hosted on my - **v1.0 (early 2021 - late 2022)**: This version was actualy hosted on my github.io page, and all the source code
github.io page, and all the source code was (and still is) avaliable, it was was (and still is) avaliable, it was just a simple static site, [here is a screenshot](assets/githubio.png).
just a simple static site, [here is a screenshot](assets/githubio.png).
- **vLOST (late 2022 - early 2023)**: As I learned more JS, I decided to rewrite - **vLOST (late 2022 - early 2023)**: As I learned more JS, I decided to rewrite (and rework) my website with one
(and rework) my website with one of the fancy JS frameworks. I decided to go of the fancy JS frameworks. I decided to go with Svelte. Not the kit version, at the time svelte did not support SSR.
with Svelte. Not the kit version, at the time svelte did not support SSR. I do I do not remember writting an API for it so I guess I just updated it everytime I wanted to add content? It was pretty
not remember writting an API for it so I guess I just updated it everytime I much like a static website and was hosted on `ngn13.fun` as at this point I had my own hosting. The source code for
wanted to add content? It was pretty much like a static website and was hosted this website was in a deleted github repository of mine, I looked for a local copy on my old hard drive but I wasn't able
on `ngn13.fun` as at this point I had my own hosting. The source code for this to find it. I also do not remember how it looked like, sooo this version is pretty much lost :(
website was in a deleted github repository of mine, I looked for a local copy
on my old hard drive but I wasn't able to find it. I also do not remember how
it looked like, sooo this version is pretty much lost :(
- **v2.0 (early 2023 - late 2023)**: After I discovered what SSR is, I decided - **v2.0 (early 2023 - late 2023)**: After I discovered what SSR is, I decided to rewrite and rework my website one more
to rewrite and rework my website one more time in NuxtJS. I had really "fun" time in NuxtJS. I had really "fun" time using vue stuff. As NuxtJS supported server-side code, this website had its own
time using vue stuff. As NuxtJS supported server-side code, this website had built in API. This website was also hosted on `ngn13.fun`. This also the first version that lives on this git repository.
its own built in API. This website was also hosted on `ngn13.fun`. This also
the first version that lives on this git repository.
- **v3.0 (2023 august - 2023 november)**: In agust of 2023, I decided to rewrite - **v3.0 (2023 august - 2023 november)**: In agust of 2023, I decided to rewrite and rework my website again, this time
and rework my website again, this time I was going with SvelteKit as I haven't I was going with SvelteKit as I haven't had the greatest experience with NuxtJS. SvelteKit was really fun to work with
had the greatest experience with NuxtJS. SvelteKit was really fun to work with and I got my new website done pretty quickly. (I don't wanna brag or something but I really imporeved the CSS/styling
and I got my new website done pretty quickly. (I don't wanna brag or something stuff ya know). I also wrote a new API with Go and Gin. I did not publish the source code for the API, the code lived
but I really imporeved the CSS/styling stuff ya know). I also wrote a new API on my local git server until I deleted it when I was done with 6.0. This website was hosted on `ngn13.fun` as well.
with Go and Gin. I did not publish the source code for the API, the code lived
on my local git server until I deleted it when I was done with 6.0. This
website was hosted on `ngn13.fun` as well.
- **v4.0 (2023 november - 2024 october)**: In this version the frontend was - **v4.0 (2023 november - 2024 october)**: In this version the frontend was still similar to 3.0, the big changes are in
still similar to 3.0, the big changes are in the API. I rewrote the API with the API. I rewrote the API with Fiber. This version was the first version hosted on `ngn.tf` which is my new domain name.
Fiber. This version was the first version hosted on `ngn.tf` which is my new Here is a [picture of the index](assets/4.0_index.png) and the [blog page](assets/4.0_blog.png).
domain name. Here is a [picture of the index](assets/4.0_index.png) and the
[blog page](assets/4.0_blog.png).
- **v5.0 (2024 october - 2025 january)**: This version just had simple frontend - **v5.0 (2024 october - 2025 january)**: This version just had simple frontend UI changes compared to 4.0, at this
UI changes compared to 4.0, at this point I was thinking about doing a massive point I was thinking about doing a massive rework (which I did with 6.0), however I was working on some other shit at
rework (which I did with 6.0), however I was working on some other shit at the the time, so I just did some small changes with the limited time I had for this project.
time, so I just did some small changes with the limited time I had for this
project.
- **v6.0 (2025 january - ...)**: The current major version of my website, - **v6.0 (2025 january - ...)**: The current major version of my website, frontend had a massive rework, API has been
frontend had a massive rework, API has been cleaned up and extended to do cleaned up and extended to do status checking for the services I host. The `doc` server has been added to the mix
status checking for the services I host. The `doc` server has been added to so I can host static documentation. The most important thing about this version is that it adds multi-language support,
the mix so I can host static documentation. The most important thing about so literally everything on the website (including the API and documentation content) is localized for both English
this version is that it adds multi-language support, so literally everything and Turkish, which was something I wanted to do for the longest time ever.
on the website (including the API and documentation content) is localized for
both English and Turkish, which was something I wanted to do for the longest Damn it has been 4 years since I wrote that shit HTML page huh? Time flies...
time ever.
## Screenshots (from v6.0)
![](assets/6.0_index.png)
![](assets/6.0_services.png)

View File

@ -1,4 +1,4 @@
FROM golang:1.24.4 FROM golang:1.24.2
WORKDIR /api WORKDIR /api

View File

@ -3,9 +3,8 @@ module github.com/ngn13/website/api
go 1.24.0 go 1.24.0
require ( require (
github.com/gofiber/fiber/v2 v2.52.8 github.com/gofiber/fiber/v2 v2.52.6
github.com/mattn/go-sqlite3 v1.14.28 github.com/mattn/go-sqlite3 v1.14.27
github.com/ngn13/ortam v0.0.0-20250421004351-8dea81680817
) )
require ( require (
@ -15,6 +14,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/ngn13/ortam v0.0.0-20250412195317-e76e62a7a305 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect

View File

@ -2,8 +2,6 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/fiber/v2 v2.52.8 h1:xl4jJQ0BV5EJTA2aWiKw/VddRpHrKeZLF0QPUxqn0x4=
github.com/gofiber/fiber/v2 v2.52.8/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
@ -17,12 +15,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/ngn13/ortam v0.0.0-20250412195317-e76e62a7a305 h1:1YxtSMwR14PklXNlZxIqcmfpiq2+G98YNmhSuz7GKCQ= github.com/ngn13/ortam v0.0.0-20250412195317-e76e62a7a305 h1:1YxtSMwR14PklXNlZxIqcmfpiq2+G98YNmhSuz7GKCQ=
github.com/ngn13/ortam v0.0.0-20250412195317-e76e62a7a305/go.mod h1:MSJZ4ZstrLvVEvivbp9hhup+iL8rvtpgKcYaF3DSOKk= github.com/ngn13/ortam v0.0.0-20250412195317-e76e62a7a305/go.mod h1:MSJZ4ZstrLvVEvivbp9hhup+iL8rvtpgKcYaF3DSOKk=
github.com/ngn13/ortam v0.0.0-20250421004351-8dea81680817 h1:WkHM4w51N5jCsWcDVcPsXz3zhi/kCfNp/VGh2uPjwsk=
github.com/ngn13/ortam v0.0.0-20250421004351-8dea81680817/go.mod h1:MSJZ4ZstrLvVEvivbp9hhup+iL8rvtpgKcYaF3DSOKk=
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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=

View File

@ -1,5 +1,5 @@
# build the application with node # build the application with node
FROM node:23.11.1 AS build FROM node:23.11.0 AS build
ARG WEBSITE_REPORT_URL ARG WEBSITE_REPORT_URL
ARG WEBSITE_SOURCE_URL ARG WEBSITE_SOURCE_URL

100
app/package-lock.json generated
View File

@ -841,11 +841,14 @@
} }
}, },
"node_modules/@sveltejs/adapter-auto": { "node_modules/@sveltejs/adapter-auto": {
"version": "6.0.1", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.0.1.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-6.0.0.tgz",
"integrity": "sha512-mcWud3pYGPWM2Pphdj8G9Qiq24nZ8L4LB7coCUckUEy5Y7wOWGJ/enaZ4AtJTcSm5dNK1rIkBRoqt+ae4zlxcQ==", "integrity": "sha512-7mR2/G7vlXakaOj6QBSG9dwBfTgWjV+UnEMB5Z6Xu0ZbdXda6c0su1fNkg0ab0zlilSkloMA2NjCna02/DR7sA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": {
"import-meta-resolve": "^4.1.0"
},
"peerDependencies": { "peerDependencies": {
"@sveltejs/kit": "^2.0.0" "@sveltejs/kit": "^2.0.0"
} }
@ -867,25 +870,23 @@
} }
}, },
"node_modules/@sveltejs/kit": { "node_modules/@sveltejs/kit": {
"version": "2.22.0", "version": "2.20.5",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.22.0.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.5.tgz",
"integrity": "sha512-DJm0UxVgzXq+1MUfiJK4Ridk7oIQsIets6JwHiEl97sI6nXScfXe+BeqNhzB7jQIVBb3BM51U4hNk8qQxRXBAA==", "integrity": "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@sveltejs/acorn-typescript": "^1.0.5",
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"acorn": "^8.14.1",
"cookie": "^0.6.0", "cookie": "^0.6.0",
"devalue": "^5.1.0", "devalue": "^5.1.0",
"esm-env": "^1.2.2", "esm-env": "^1.2.2",
"import-meta-resolve": "^4.1.0",
"kleur": "^4.1.5", "kleur": "^4.1.5",
"magic-string": "^0.30.5", "magic-string": "^0.30.5",
"mrmime": "^2.0.0", "mrmime": "^2.0.0",
"sade": "^1.8.1", "sade": "^1.8.1",
"set-cookie-parser": "^2.6.0", "set-cookie-parser": "^2.6.0",
"sirv": "^3.0.0", "sirv": "^3.0.0"
"vitefu": "^1.0.6"
}, },
"bin": { "bin": {
"svelte-kit": "svelte-kit.js" "svelte-kit": "svelte-kit.js"
@ -894,9 +895,9 @@
"node": ">=18.13" "node": ">=18.13"
}, },
"peerDependencies": { "peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0",
"svelte": "^4.0.0 || ^5.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0",
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" "vite": "^5.0.3 || ^6.0.0"
} }
}, },
"node_modules/@sveltejs/vite-plugin-svelte": { "node_modules/@sveltejs/vite-plugin-svelte": {
@ -965,10 +966,9 @@
"optional": true "optional": true
}, },
"node_modules/acorn": { "node_modules/acorn": {
"version": "8.14.1", "version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
"license": "MIT",
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@ -1084,9 +1084,9 @@
"dev": true "dev": true
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.2.6", "version": "3.2.5",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.6.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.5.tgz",
"integrity": "sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==", "integrity": "sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==",
"license": "(MPL-2.0 OR Apache-2.0)", "license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": { "optionalDependencies": {
"@types/trusted-types": "^2.0.7" "@types/trusted-types": "^2.0.7"
@ -1204,9 +1204,9 @@
} }
}, },
"node_modules/esrap": { "node_modules/esrap": {
"version": "1.4.9", "version": "1.4.6",
"resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.9.tgz", "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz",
"integrity": "sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g==", "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15" "@jridgewell/sourcemap-codec": "^1.4.15"
@ -1299,6 +1299,17 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/import-meta-resolve": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
"integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==",
"dev": true,
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/intl-messageformat": { "node_modules/intl-messageformat": {
"version": "10.7.11", "version": "10.7.11",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.11.tgz", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.11.tgz",
@ -1385,9 +1396,9 @@
} }
}, },
"node_modules/marked": { "node_modules/marked": {
"version": "15.0.12", "version": "15.0.9",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.9.tgz",
"integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "integrity": "sha512-9AW/bn9DxQeZVjR52l5jsc0W2pwuhP04QaQewPvylil12Cfr2GBfWmgp6mu8i9Jy8UlBjqDZ9uMTDuJ8QOGZJA==",
"license": "MIT", "license": "MIT",
"bin": { "bin": {
"marked": "bin/marked.js" "marked": "bin/marked.js"
@ -1516,9 +1527,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "3.6.2", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"bin": { "bin": {
@ -1532,9 +1543,9 @@
} }
}, },
"node_modules/prettier-plugin-svelte": { "node_modules/prettier-plugin-svelte": {
"version": "3.4.0", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz",
"integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peerDependencies": { "peerDependencies": {
@ -1650,9 +1661,9 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "5.34.7", "version": "5.26.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.34.7.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.26.2.tgz",
"integrity": "sha512-5PEg+QQKce4t1qiOtVUhUS3AQRTtxJyGBTpxLcNWnr0Ve8q4r06bMo0Gv8uhtCPWlztZHoi3Ye7elLhu+PCTMg==", "integrity": "sha512-e2TEcGK2YKVwDWYy5OsptVclYgDvfY1E/8IzPiOq63uG/GDo/j5VUYTC9EinQNraoZalbMWN+5f5TYC1QlAqOw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.3.0", "@ampproject/remapping": "^2.3.0",
@ -1664,7 +1675,7 @@
"axobject-query": "^4.1.0", "axobject-query": "^4.1.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"esm-env": "^1.2.1", "esm-env": "^1.2.1",
"esrap": "^1.4.8", "esrap": "^1.4.6",
"is-reference": "^3.0.3", "is-reference": "^3.0.3",
"locate-character": "^3.0.0", "locate-character": "^3.0.0",
"magic-string": "^0.30.11", "magic-string": "^0.30.11",
@ -2149,9 +2160,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "5.4.19", "version": "5.4.18",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz",
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2209,17 +2220,12 @@
} }
}, },
"node_modules/vitefu": { "node_modules/vitefu": {
"version": "1.0.6", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.3.tgz",
"integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", "integrity": "sha512-iKKfOMBHob2WxEJbqbJjHAkmYgvFDPhuqrO82om83S8RLk+17FtyMBfcyeH8GqD0ihShtkMW/zzJgiA51hCNCQ==",
"dev": true, "dev": true,
"license": "MIT",
"workspaces": [
"tests/deps/*",
"tests/projects/*"
],
"peerDependencies": { "peerDependencies": {
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0-beta.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"vite": { "vite": {

BIN
assets/6.0_index.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
assets/6.0_services.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -81,7 +81,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon BreakInheritanceList: BeforeColon
BreakStringLiterals: true BreakStringLiterals: true
ColumnLimit: 80 ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false CompactNamespaces: false
ConstructorInitializerIndentWidth: 4 ConstructorInitializerIndentWidth: 4

View File

@ -1,35 +0,0 @@
---
# "gnu-zero-variadic-macro-arguments" ignored because we are using GNU99
# standart
# "clang-diagnostic-language-extension-token" is ignored because we need the
# asm() extension token
# "DeprecatedOrUnsafeBufferHandling" ignored because C11 "_s" functions are not
# secure either
Checks: >-
clang-diagnostic-*,
-clang-diagnostic-gnu-zero-variadic-macro-arguments,
-clang-diagnostic-language-extension-token,
clang-analyzer-*,
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
portability-*,
performance-*,
WarningsAsErrors: '*'
HeaderFileExtensions:
- ''
- h
- hh
- hpp
- hxx
ImplementationFileExtensions:
- c
- cc
- cpp
- cxx
HeaderFilterRegex: '.*'
ExcludeHeaderFilterRegex: ''
FormatStyle: file
SystemHeaders: false
...

View File

@ -1,9 +1,9 @@
FROM ghcr.io/ngn13/ctorm:1.8.1 FROM ghcr.io/ngn13/ctorm:1.7
WORKDIR /doc WORKDIR /doc
COPY Makefile ./ COPY Makefile ./
COPY pages ./pages COPY docs ./docs
COPY inc ./inc COPY inc ./inc
COPY src ./src COPY src ./src

View File

@ -26,13 +26,10 @@ $(DISTDIR)/%.o: src/%.c
format: format:
clang-format -i -style=file $(CSRCS) $(HSRCS) clang-format -i -style=file $(CSRCS) $(HSRCS)
lint:
clang-tidy --warnings-as-errors --config= $(CSRCS) $(HSRCS)
clean: clean:
rm -rf $(DISTDIR) rm -rf $(DISTDIR)
run: run:
./doc.elf ./doc.elf
.PHONY: format lint clean run .PHONY: format clean run

4
doc/docs/privacy.en.json Normal file
View File

@ -0,0 +1,4 @@
{
"title": "privacy",
"desc": "Learn how I respect your privacy"
}

4
doc/docs/privacy.tr.json Normal file
View File

@ -0,0 +1,4 @@
{
"title": "gizlilik",
"desc": "Gizliliğinize nasıl önem verdiğimi öğrenin"
}

View File

@ -3,13 +3,13 @@
#include <stdbool.h> #include <stdbool.h>
#include <dirent.h> #include <dirent.h>
#include "file.h" #include "util.h"
typedef struct { typedef struct {
DIR *dir; DIR *dir;
file_t *file; util_file_t *file;
char name[NAME_MAX + 1]; char name[NAME_MAX + 1];
char *lang; char *lang;
} docs_t; } docs_t;
bool docs_init(docs_t *docs, char *dir); bool docs_init(docs_t *docs, char *dir);

View File

@ -1,10 +0,0 @@
#pragma once
#include <stdint.h>
typedef struct {
char *content;
int64_t size;
} file_t;
file_t *file_load(int dirfd, char *path);
void file_free(file_t *file);

View File

@ -4,8 +4,16 @@
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#define util_toupper(str) \ typedef struct {
for (char *c = str; *c != 0; c++) \ char *content;
uint64_t size;
} util_file_t;
#define util_toupper(str) \
for (char *c = str; *c != 0; c++) \
*c = toupper(*c) *c = toupper(*c)
uint64_t util_endswith(char *str, char *suf); uint64_t util_endswith(char *str, char *suf);
void util_send(ctorm_res_t *res, uint16_t code, cJSON *json); void util_send(ctorm_res_t *res, uint16_t code, cJSON *json);
util_file_t *util_file_load(int dirfd, char *path);
void util_file_free(util_file_t *file);
bool util_parse_doc_name(char *name, char **lang, const char *ext);

View File

@ -1,4 +0,0 @@
{
"title": "privacy",
"desc": "Privacy policy"
}

View File

@ -1,4 +0,0 @@
{
"title": "gizlilik",
"desc": "Gizlilik ilkesi"
}

View File

@ -11,25 +11,22 @@
option_t options[] = { option_t options[] = {
// name value requied // name value requied
{"host", "0.0.0.0:7003", true }, // host the server should listen on {"host", "0.0.0.0:7003", true }, // host the server should listen on
{"dir", "./pages", true }, // documentation pages directory {"docs_dir", "./docs", true }, // documentation directory
{"", NULL, false}, {"", NULL, false},
}; };
bool config_load(config_t *conf) { bool config_load(config_t *conf) {
memset(conf, 0, sizeof(*conf)); bzero(conf, sizeof(*conf));
char name_env[OPT_NAME_MAX + 10], name_copy[OPT_NAME_MAX], *value = NULL; char name_env[OPT_NAME_MAX + 10], name_copy[OPT_NAME_MAX], *value = NULL;
conf->options = options; conf->options = options;
for (option_t *opt = conf->options; opt->value != NULL; for (option_t *opt = conf->options; opt->value != NULL; opt++, conf->count++) {
opt++, conf->count++) { strcpy(name_copy, opt->name);
// convert option name to environment variable name
strncpy(name_copy, opt->name, OPT_NAME_MAX);
util_toupper(name_copy); util_toupper(name_copy);
snprintf(name_env, sizeof(name_env), "WEBSITE_%s", name_copy); snprintf(name_env, sizeof(name_env), "WEBSITE_%s", name_copy);
// attempt to load the value from the environment
if ((value = getenv(name_env)) != NULL) if ((value = getenv(name_env)) != NULL)
opt->value = value; opt->value = value;
@ -39,9 +36,7 @@ bool config_load(config_t *conf) {
if (!opt->required || NULL != opt->value) if (!opt->required || NULL != opt->value)
continue; continue;
ctorm_fail("please specify a value for the required config option: %s (%s)", ctorm_fail("please specify a value for the required config option: %s (%s)", opt->name, name_env);
opt->name,
name_env);
errno = EFAULT; errno = EFAULT;
return false; return false;
} }

View File

@ -1,6 +1,6 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <dirent.h> #include <dirent.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@ -9,7 +9,7 @@
#define DOCS_LANG_CODE_LEN 2 #define DOCS_LANG_CODE_LEN 2
bool _docs_parse_name(docs_t *docs, char *ext) { bool __docs_parse_name(docs_t *docs, char *ext) {
// check the extension // check the extension
uint64_t ext_pos = util_endswith(docs->name, ext); uint64_t ext_pos = util_endswith(docs->name, ext);
@ -22,8 +22,7 @@ bool _docs_parse_name(docs_t *docs, char *ext) {
// example.en\0json\0 // example.en\0json\0
// | // |
// `--- find this // `--- find this
for (docs->lang = docs->name; *docs->lang != 0 && *docs->lang != '.'; for (docs->lang = docs->name; *docs->lang != 0 && *docs->lang != '.'; docs->lang++)
docs->lang++)
continue; continue;
if (*docs->lang != '.') if (*docs->lang != '.')
@ -40,11 +39,11 @@ bool _docs_parse_name(docs_t *docs, char *ext) {
return strlen(docs->lang) == DOCS_LANG_CODE_LEN && *docs->name != 0; return strlen(docs->lang) == DOCS_LANG_CODE_LEN && *docs->name != 0;
} }
void _docs_clean(docs_t *docs) { void __docs_clean(docs_t *docs) {
if (NULL == docs->file) if (NULL == docs->file)
return; return;
file_free(docs->file); util_file_free(docs->file);
docs->file = NULL; docs->file = NULL;
} }
@ -54,7 +53,7 @@ bool docs_init(docs_t *docs, char *dir) {
return false; return false;
} }
memset(docs, 0, sizeof(*docs)); bzero(docs, sizeof(*docs));
return NULL != (docs->dir = opendir(dir)); return NULL != (docs->dir = opendir(dir));
} }
@ -65,15 +64,15 @@ char *docs_next(docs_t *docs, char *name, bool content) {
} }
struct dirent *ent = NULL; struct dirent *ent = NULL;
_docs_clean(docs); __docs_clean(docs);
while (NULL != (ent = readdir(docs->dir))) { while (NULL != (ent = readdir(docs->dir))) {
if (*ent->d_name == '.') if (*ent->d_name == '.')
continue; continue;
strncpy(docs->name, ent->d_name, NAME_MAX); strcpy(docs->name, ent->d_name);
if (!_docs_parse_name(docs, content ? ".md" : ".json")) if (!__docs_parse_name(docs, content ? ".md" : ".json"))
continue; continue;
if (NULL == name || strncmp(docs->name, name, NAME_MAX) == 0) if (NULL == name || strncmp(docs->name, name, NAME_MAX) == 0)
@ -85,7 +84,7 @@ char *docs_next(docs_t *docs, char *name, bool content) {
return NULL; return NULL;
} }
if (NULL == (docs->file = file_load(dirfd(docs->dir), ent->d_name))) if (NULL == (docs->file = util_file_load(dirfd(docs->dir), ent->d_name)))
return NULL; return NULL;
return docs->file->content; return docs->file->content;
@ -100,8 +99,8 @@ void docs_free(docs_t *docs) {
if (NULL == docs) if (NULL == docs)
return; return;
_docs_clean(docs); __docs_clean(docs);
closedir(docs->dir); closedir(docs->dir);
memset(docs, 0, sizeof(*docs)); bzero(docs, sizeof(*docs));
} }

View File

@ -1,56 +0,0 @@
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include "file.h"
file_t *file_load(int dirfd, char *path) {
if (NULL == path) {
errno = EINVAL;
return NULL;
}
file_t *file = NULL;
int fd = -1;
// open the taarget file
if ((fd = openat(dirfd, path, O_RDONLY)) < 0)
goto end; // errno set by open
// allocate a new file structure
if (NULL == (file = calloc(1, sizeof(file_t))))
goto end; // errno set by malloc
// calculate the file size
if ((file->size = lseek(fd, 0, SEEK_END)) < 0)
goto end;
// memory map the file
if (NULL ==
(file->content = mmap(0, file->size, PROT_READ, MAP_PRIVATE, fd, 0)))
goto end; // errno set by mmap
end:
if (fd != -1)
close(fd);
if (NULL != file && NULL == file->content) {
free(file);
return NULL;
}
return file;
}
void file_free(file_t *file) {
if (NULL == file)
return;
munmap(file->content, file->size);
free(file);
}

View File

@ -1,4 +1,3 @@
#include <ctorm/app.h>
#include <ctorm/ctorm.h> #include <ctorm/ctorm.h>
#include <stdlib.h> #include <stdlib.h>
@ -20,28 +19,25 @@ int main() {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// initialize the app config
ctorm_config_new(&app_config); ctorm_config_new(&app_config);
app_config.disable_logging = true; app_config.disable_logging = true;
app = ctorm_app_new(&app_config);
// create a new app
app = ctorm_app_new(&app_config);
// middlewares // middlewares
ALL(app, "/*", route_cors); MIDDLEWARE_ALL(app, "/*", route_cors);
ALL(app, "/*/*", route_cors); MIDDLEWARE_ALL(app, "/*/*", route_cors);
// routes // routes
GET(app, "/list", route_list); GET(app, "/list", route_list);
GET(app, "/get/:name", route_get); GET(app, "/get/:name", route_get);
ctorm_app_default(app, route_notfound); ctorm_app_all(app, route_notfound);
ctorm_app_local(app, "config", &conf); ctorm_app_local(app, "config", &conf);
ctorm_info("starting the web server on %s", host); ctorm_info("starting the web server on %s", host);
if (!ctorm_app_run(app, host)) if (!ctorm_app_run(app, host))
ctorm_fail("failed to start the app: %s", ctorm_error()); ctorm_fail("failed to start the app: %s", ctorm_geterror());
ctorm_app_free(app); ctorm_app_free(app);
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -3,8 +3,7 @@
void route_cors(ctorm_req_t *req, ctorm_res_t *res) { void route_cors(ctorm_req_t *req, ctorm_res_t *res) {
RES_SET("Access-Control-Allow-Origin", "*"); RES_SET("Access-Control-Allow-Origin", "*");
RES_SET("Access-Control-Allow-Headers", RES_SET("Access-Control-Allow-Headers",
"Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, " "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, "
"Authorization, accept, origin, Cache-Control, "
"X-Requested-With"); "X-Requested-With");
RES_SET("Access-Control-Allow-Methods", "PUT, DELETE, GET"); RES_SET("Access-Control-Allow-Methods", "PUT, DELETE, GET");
} }

View File

@ -1,30 +1,31 @@
#include <linux/limits.h>
#include <cjson/cJSON.h> #include <cjson/cJSON.h>
#include <dirent.h>
#include <linux/limits.h>
#include <ctorm/ctorm.h> #include <ctorm/ctorm.h>
#include <dirent.h> #include <string.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "routes.h" #include "routes.h"
#include "config.h" #include "config.h"
#include "util.h"
#include "docs.h" #include "docs.h"
void route_get(ctorm_req_t *req, ctorm_res_t *res) { void route_get(ctorm_req_t *req, ctorm_res_t *res) {
config_t *conf = REQ_LOCAL("config"); config_t *conf = REQ_LOCAL("config");
char *name = REQ_PARAM("name"); char *doc_name = REQ_PARAM("name");
char *dir = config_get(conf, "dir"), *doc_data = NULL; char *docs_dir = config_get(conf, "docs_dir"), *doc_data = NULL;
cJSON *json = NULL, *doc_json = NULL; cJSON *json = NULL, *doc_json = NULL;
docs_t docs; docs_t docs;
if (NULL == name) { if (NULL == doc_name) {
ctorm_fail("documentation name not specified (how did that even happend)"); ctorm_fail("documentation name not specified (how did that even happend)");
util_send(res, 500, NULL); util_send(res, 500, NULL);
goto end; goto end;
} }
if (!docs_init(&docs, dir)) { if (!docs_init(&docs, docs_dir)) {
ctorm_fail("docs_init failed: %s", ctorm_error()); ctorm_fail("docs_init failed: %s", ctorm_geterror());
util_send(res, 500, NULL); util_send(res, 500, NULL);
goto end; goto end;
} }
@ -35,7 +36,7 @@ void route_get(ctorm_req_t *req, ctorm_res_t *res) {
goto end; goto end;
} }
while (NULL != (doc_data = docs_next(&docs, name, false))) { while (NULL != (doc_data = docs_next(&docs, doc_name, false))) {
if (NULL == (doc_json = cJSON_Parse(doc_data))) { if (NULL == (doc_json = cJSON_Parse(doc_data))) {
ctorm_fail("failed to parse JSON: %s (%s)", docs.name, docs.lang); ctorm_fail("failed to parse JSON: %s (%s)", docs.name, docs.lang);
continue; continue;
@ -52,7 +53,7 @@ void route_get(ctorm_req_t *req, ctorm_res_t *res) {
docs_reset(&docs); docs_reset(&docs);
while (NULL != (doc_data = docs_next(&docs, name, true))) { while (NULL != (doc_data = docs_next(&docs, doc_name, true))) {
if (NULL == (doc_json = cJSON_GetObjectItem(json, docs.lang))) if (NULL == (doc_json = cJSON_GetObjectItem(json, docs.lang)))
continue; continue;

View File

@ -3,21 +3,21 @@
#include <ctorm/ctorm.h> #include <ctorm/ctorm.h>
#include <dirent.h> #include <dirent.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include "routes.h" #include "routes.h"
#include "config.h" #include "config.h"
#include "util.h"
#include "docs.h" #include "docs.h"
void route_list(ctorm_req_t *req, ctorm_res_t *res) { void route_list(ctorm_req_t *req, ctorm_res_t *res) {
config_t *conf = REQ_LOCAL("config"); config_t *conf = REQ_LOCAL("config");
char *dir = config_get(conf, "dir"), *doc_data = NULL; char *docs_dir = config_get(conf, "docs_dir"), *doc_data = NULL;
cJSON *array = NULL, *json = NULL, *doc_json = NULL; cJSON *array = NULL, *json = NULL, *doc_json = NULL;
docs_t docs; docs_t docs;
if (!docs_init(&docs, dir)) { if (!docs_init(&docs, docs_dir)) {
ctorm_fail("docs_init failed: %s", ctorm_error()); ctorm_fail("docs_init failed: %s", ctorm_geterror());
util_send(res, 500, NULL); util_send(res, 500, NULL);
goto end; goto end;
} }
@ -31,8 +31,7 @@ void route_list(ctorm_req_t *req, ctorm_res_t *res) {
while (NULL != (doc_data = docs_next(&docs, NULL, false))) { while (NULL != (doc_data = docs_next(&docs, NULL, false))) {
if (NULL == (array = cJSON_GetObjectItem(json, docs.lang)) && if (NULL == (array = cJSON_GetObjectItem(json, docs.lang)) &&
NULL == (array = cJSON_AddArrayToObject(json, docs.lang))) { NULL == (array = cJSON_AddArrayToObject(json, docs.lang))) {
ctorm_fail( ctorm_fail("failed to create an array object for the language %s", docs.lang);
"failed to create an array object for the language %s", docs.lang);
continue; continue;
} }

View File

@ -1,8 +1,17 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <ctorm/ctorm.h> #include <ctorm/ctorm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdint.h> #include <stdint.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include "util.h" #include "util.h"
@ -48,3 +57,45 @@ void util_send(ctorm_res_t *res, uint16_t code, cJSON *json) {
RES_JSON(json); RES_JSON(json);
} }
util_file_t *util_file_load(int dirfd, char *path) {
if (NULL == path) {
errno = EINVAL;
return NULL;
}
util_file_t *file = NULL;
struct stat buf;
int fd = -1;
if (NULL == (file = malloc(sizeof(util_file_t))))
goto end; // errno set by malloc
if ((fd = openat(dirfd, path, O_RDONLY)) < 0)
goto end; // errno set by open
if (fstat(fd, &buf) < 0)
goto end; // errno set by fstat
if (NULL == (file->content = mmap(0, (file->size = buf.st_size), PROT_READ, MAP_PRIVATE, fd, 0)))
goto end; // errno set by mmap
end:
if (fd != -1)
close(fd);
if (NULL == file->content) {
free(file);
return NULL;
}
return file;
}
void util_file_free(util_file_t *file) {
if (NULL == file)
return;
munmap(file->content, file->size);
free(file);
}