Compare commits
19 Commits
feature/ex
...
f2eaac460d
| Author | SHA1 | Date | |
|---|---|---|---|
| f2eaac460d | |||
| babddc6838 | |||
| 2ce492e2ea | |||
| 450a841385 | |||
| d23ea2eea1 | |||
| 76b3af3e55 | |||
| ef04e95c4e | |||
| 5d6dc6f50e | |||
| 3ea33fc34e | |||
| 9508911c19 | |||
| 3bbf1a2bfa | |||
| c56c6c39ed | |||
| 280957ca22 | |||
| c2c452510b | |||
| 69744cda5f | |||
| b2660c125c | |||
| 9895782b0a | |||
| 8bca3eb2fe | |||
| 952a1075bf |
28
.gitea/workflows/ci.yaml
Normal file
28
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Build container
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: citadel-container-builder
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install qemu dependency
|
||||||
|
run: |
|
||||||
|
sudo dnf install -y qemu-user-static-aarch64
|
||||||
|
- name: Build
|
||||||
|
uses: redhat-actions/buildah-build@v2
|
||||||
|
with:
|
||||||
|
image: ${{ github.repository_owner }}/${{ github.event.repository.name }}
|
||||||
|
tags: latest
|
||||||
|
archs: arm64
|
||||||
|
containerfiles: |
|
||||||
|
./Containerfile
|
||||||
|
- name: Push
|
||||||
|
uses: redhat-actions/push-to-registry@v2
|
||||||
|
with:
|
||||||
|
image: ${{ github.repository_owner }}/${{ github.event.repository.name }}
|
||||||
|
tags: latest
|
||||||
|
registry: git.plabble.org
|
||||||
|
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||||
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
FROM node:21-alpine3.19 AS frontend-builder
|
FROM node:22-alpine3.20 AS frontend-builder
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
COPY pastabble-frontend/ .
|
COPY pastabble-frontend/ .
|
||||||
RUN pnpm i && pnpm build
|
RUN pnpm i && pnpm build
|
||||||
|
|
||||||
FROM rust:alpine3.19 AS builder
|
FROM rust:alpine3.20 AS builder
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
RUN apk add --no-cache musl-dev
|
RUN apk add --no-cache musl-dev
|
||||||
@@ -18,7 +18,7 @@ RUN case "$(apk --print-arch)" in \
|
|||||||
mv ./target/aarch64-unknown-linux-musl /release ;; \
|
mv ./target/aarch64-unknown-linux-musl /release ;; \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
FROM alpine:3.19
|
FROM alpine:3.20
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN mkdir wwwroot data && \
|
RUN mkdir wwwroot data && \
|
||||||
|
|||||||
@@ -10,20 +10,20 @@
|
|||||||
"check": "svelte-check --tsconfig ./tsconfig.json"
|
"check": "svelte-check --tsconfig ./tsconfig.json"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.1",
|
"@sveltejs/vite-plugin-svelte": "^5.1.0",
|
||||||
"@tsconfig/svelte": "^5.0.2",
|
"@tsconfig/svelte": "^5.0.4",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.21",
|
||||||
"daisyui": "^4.6.1",
|
"daisyui": "^4.12.24",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.5.4",
|
||||||
"svelte": "^4.2.8",
|
"svelte": "^5.33.14",
|
||||||
"svelte-check": "^3.6.2",
|
"svelte-check": "^4.2.1",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.17",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^5.0.8"
|
"vite": "^6.3.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.11.1",
|
||||||
"svelte-spa-router": "^4.0.1"
|
"svelte-spa-router": "^4.0.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2439
pastabble-frontend/pnpm-lock.yaml
generated
2439
pastabble-frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,8 @@
|
|||||||
import './app.css'
|
import './app.css'
|
||||||
import 'highlight.js/styles/github-dark.min.css';
|
import 'highlight.js/styles/github-dark.min.css';
|
||||||
|
import { mount } from 'svelte';
|
||||||
import App from './App.svelte'
|
import App from './App.svelte'
|
||||||
|
|
||||||
const app = new App({
|
const app = mount(App, { target: document.getElementById("app") });
|
||||||
target: document.getElementById('app'),
|
|
||||||
})
|
|
||||||
|
|
||||||
export default app
|
export default app
|
||||||
|
|||||||
45
src/main.rs
45
src/main.rs
@@ -1,10 +1,10 @@
|
|||||||
use std::{collections::HashMap, env, fs::{self, File}, sync::{Arc, Mutex}, thread};
|
use std::{env, fs::{self, File}, thread};
|
||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use kv::{Config, Store, Json, Bucket, Value};
|
use kv::{Config, Store, Json, Bucket, Value};
|
||||||
use paste::Paste;
|
use paste::Paste;
|
||||||
use rand::{Rng, distributions::Alphanumeric};
|
use rand::{Rng, distributions::Alphanumeric};
|
||||||
use rouille::{post_input, router, try_or_400, websocket, Request, Response, Server};
|
use rouille::{Response, router, try_or_400, post_input, Request, Server};
|
||||||
use signal_hook::{iterator::Signals, consts::{SIGINT, SIGTERM}};
|
use signal_hook::{iterator::Signals, consts::{SIGINT, SIGTERM}};
|
||||||
|
|
||||||
mod paste;
|
mod paste;
|
||||||
@@ -30,7 +30,6 @@ fn generate_key<T : Value>(key: Option<String>, store: &Bucket<String, T>) -> St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get query parameters
|
|
||||||
fn get_query(req: &Request, name: &str) -> Option<String> {
|
fn get_query(req: &Request, name: &str) -> Option<String> {
|
||||||
let params: Vec<&str> = req.raw_query_string().split('&').collect();
|
let params: Vec<&str> = req.raw_query_string().split('&').collect();
|
||||||
let param = params.iter().find(|p|p.starts_with(&format!("{}=", name)));
|
let param = params.iter().find(|p|p.starts_with(&format!("{}=", name)));
|
||||||
@@ -59,8 +58,6 @@ fn main() {
|
|||||||
let links = store.bucket::<String, String>(Some("links"))
|
let links = store.bucket::<String, String>(Some("links"))
|
||||||
.expect("Failed to open links bucket");
|
.expect("Failed to open links bucket");
|
||||||
|
|
||||||
// Temp pastes
|
|
||||||
let temp_pastes = Arc::new(Mutex::new(HashMap::new()));
|
|
||||||
|
|
||||||
// Create server
|
// Create server
|
||||||
let server = Server::new(format!("0.0.0.0:{}", port), move |req| {
|
let server = Server::new(format!("0.0.0.0:{}", port), move |req| {
|
||||||
@@ -71,10 +68,6 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.url().starts_with("/ws") {
|
|
||||||
handle_websocket(temp_pastes.clone(), &req);
|
|
||||||
}
|
|
||||||
|
|
||||||
router!(req,
|
router!(req,
|
||||||
(GET) (/) => {
|
(GET) (/) => {
|
||||||
match File::open(format!("{}/index.html", &source_dir)) {
|
match File::open(format!("{}/index.html", &source_dir)) {
|
||||||
@@ -122,7 +115,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
(POST) (/{id: String}) => {
|
(POST) (/{id: String}) => {
|
||||||
let id = if id.is_empty() { None } else { Some(id) };
|
let id = if id.is_empty() { None } else { Some(id) };
|
||||||
register_paste(&pastes, req, id, prefix.clone(), None)
|
register_paste(&pastes, req, id, prefix.clone())
|
||||||
},
|
},
|
||||||
_ => Response::empty_404()
|
_ => Response::empty_404()
|
||||||
)
|
)
|
||||||
@@ -150,7 +143,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register paste handler
|
// Register paste handler
|
||||||
fn register_paste(pastes: &Bucket<String, Json<Paste>>, req: &Request, id: Option<String>, prefix: Option<String>, allow_edit: Option<bool>) -> Response {
|
fn register_paste(pastes: &Bucket<String, Json<Paste>>, req: &Request, id: Option<String>, prefix: Option<String>) -> Response {
|
||||||
|
|
||||||
// Try read body from form data, and if not present from request body
|
// Try read body from form data, and if not present from request body
|
||||||
let body = match post_input!(req, {
|
let body = match post_input!(req, {
|
||||||
content: String
|
content: String
|
||||||
@@ -171,7 +165,6 @@ fn register_paste(pastes: &Bucket<String, Json<Paste>>, req: &Request, id: Optio
|
|||||||
content: body,
|
content: body,
|
||||||
expires: None,
|
expires: None,
|
||||||
language,
|
language,
|
||||||
allow_edit,
|
|
||||||
created: Utc::now()
|
created: Utc::now()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -217,31 +210,3 @@ fn register_link(links: &Bucket<String,String>, req: &Request, id: Option<String
|
|||||||
|
|
||||||
Response::text(url)
|
Response::text(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_websocket(pastes: Arc<Mutex<HashMap<String, String>>>, req: &Request) -> Response {
|
|
||||||
let key = get_query(&req, "key").unwrap();
|
|
||||||
|
|
||||||
let mut current_text = String::new();
|
|
||||||
match pastes.lock().expect("Failed to access pastes DB").get(&key) {
|
|
||||||
Some(paste) => {
|
|
||||||
current_text = paste.clone()
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
// OK, ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (response, websocket) = try_or_400!(websocket::start(req, Some("pastabble")));
|
|
||||||
if let Ok(mut ws) = websocket.recv() {
|
|
||||||
thread::spawn(move || {
|
|
||||||
if !current_text.is_empty() {
|
|
||||||
_ = ws.send_text(¤t_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
return response.with_additional_header("Access-Control-Allow-Origin", "*");
|
|
||||||
} else {
|
|
||||||
return Response::empty_400()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,5 @@ pub struct Paste {
|
|||||||
|
|
||||||
#[serde(with = "ts_seconds_option")]
|
#[serde(with = "ts_seconds_option")]
|
||||||
pub expires: Option<DateTime<Utc>>,
|
pub expires: Option<DateTime<Utc>>,
|
||||||
pub created: DateTime<Utc>,
|
pub created: DateTime<Utc>
|
||||||
|
|
||||||
pub allow_edit: Option<bool>
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user