Compare commits

..

10 commits

6 changed files with 74 additions and 16 deletions

2
Cargo.lock generated
View file

@ -740,7 +740,7 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "kosyncrs"
version = "1.1.1"
version = "2.0.0"
dependencies = [
"axum",
"serde",

View file

@ -1,6 +1,6 @@
[package]
name = "kosyncrs"
version = "1.1.1"
version = "2.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View file

@ -28,14 +28,14 @@ Connect to the database as user *kosync* (with psql) and create the database tab
```sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL,
username TEXT UNIQUE NOT NULL,
password TEXT
);
CREATE TABLE progresses (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
document TEXT UNIQUE NOT NULL,
document TEXT NOT NULL,
progress TEXT NOT NULL,
percentage REAL NOT NULL,
device TEXT NOT NULL,
@ -45,4 +45,4 @@ CREATE TABLE progresses (
REFERENCES users(id) ON DELETE CASCADE,
UNIQUE (user_id, document)
);
```
```

52
python/redis2pg.py Normal file
View file

@ -0,0 +1,52 @@
#!/usr/bin/env python3
import psycopg2
import re
import redis
con = redis.Redis()
pgcon = psycopg2.connect("postgresql://kosync:mypassword@localhost/kosync")
pgcur = pgcon.cursor()
userkeys = con.keys('user:*:key')
for key in userkeys:
key = key.decode('utf-8')
match = re.search('user:(.*):key', key)
username = match.group(1)
password = con.get(key).decode('utf-8')
documentkeys = con.keys('user:' + username + ':document:*')
if len(documentkeys) == 0:
print("Skipped:", username)
continue
pgcur.execute("INSERT INTO users (username, password) VALUES (%s, %s) ON CONFLICT (username) DO UPDATE SET username = %s, password = %s",
(username, password, username, password))
pgcur.execute("SELECT id FROM users WHERE username = %s", (username,))
res = pgcur.fetchone()
user_id = res[0]
for dockey in documentkeys:
dockey = dockey.decode('utf-8')
match = re.search("user:.*:(.*)", dockey)
document = match.group(1)
docvals = con.hgetall(dockey)
progress = docvals[b"progress"].decode()
percentage = docvals[b"percentage"].decode()
device = docvals[b"device"].decode()
device_id = docvals[b"device_id"].decode()
timestamp = docvals[b"timestamp"].decode()
pgcur.execute("INSERT INTO progresses (user_id, document, progress, percentage, device, device_id, timestamp) VALUES (%s, %s, %s, %s, %s, %s, %s) ON CONFLICT (user_id, document) DO UPDATE SET user_id = %s, document = %s, progress = %s, percentage = %s, device = %s, device_id = %s, timestamp = %s",
(user_id, document, progress, percentage, device, device_id, timestamp, user_id, document, progress, percentage, device, device_id, timestamp))
pgcon.commit()
pgcur.close()
pgcon.close()

View file

@ -39,12 +39,15 @@ pub struct GetProgress {
timestamp: i64,
}
const VERSION: &str = env!("CARGO_PKG_VERSION");
#[tokio::main]
async fn main() {
let pg_url: String = env::var("PG_URL")
.ok()
.and_then(|v| v.parse().ok())
.unwrap();
let listen_port: String = env::var("PORT").ok().and_then(|v| v.parse().ok()).unwrap();
let db_pool = PgPoolOptions::new()
.max_connections(64)
@ -61,10 +64,12 @@ async fn main() {
.route("/syncs/progress", put(update_progress))
.route("/syncs/progress/{document}", get(get_progress))
.route("/healthcheck", get(healthcheck))
.route("/version", get(version))
.with_state(db_pool);
// run it with hyper on localhost:3003
let listener = tokio::net::TcpListener::bind("127.0.0.1:3003")
let mut bind_with = "127.0.0.1:".to_owned();
bind_with += &listen_port;
let listener = tokio::net::TcpListener::bind(bind_with)
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
@ -74,14 +79,15 @@ async fn root() -> &'static str {
"KOreader sync server"
}
async fn version() -> &'static str {
VERSION
}
async fn create_user(
State(db_pool): State<PgPool>,
Json(payload): Json<User>,
) -> (StatusCode, Json<Value>) {
//let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//let mut con = client.get_connection().unwrap();
let username = payload.username;
let username = payload.username.trim().to_owned();
let password = payload.password;
let row: (i64,) = sqlx::query_as("SELECT COUNT(id) FROM users WHERE username = $1")
@ -128,7 +134,7 @@ async fn authorize(db: impl PgExecutor<'_>, username: &str, password: &str) -> b
}
async fn auth_user(State(db_pool): State<PgPool>, headers: HeaderMap) -> (StatusCode, Json<Value>) {
let username = headers["x-auth-user"].to_str().unwrap_or("");
let username = headers["x-auth-user"].to_str().unwrap_or("").trim();
let password = headers["x-auth-key"].to_str().unwrap_or("");
let mut tx = db_pool.begin().await.unwrap();
@ -150,7 +156,7 @@ async fn update_progress(
headers: HeaderMap,
Json(payload): Json<UpdateProgress>,
) -> StatusCode {
let username = headers["x-auth-user"].to_str().unwrap_or("");
let username = headers["x-auth-user"].to_str().unwrap_or("").trim();
let password = headers["x-auth-key"].to_str().unwrap_or("");
let mut tx = db_pool.begin().await.unwrap();
@ -196,7 +202,7 @@ async fn get_progress(
headers: HeaderMap,
Path(document): Path<String>,
) -> (StatusCode, Json<Value>) {
let username = headers["x-auth-user"].to_str().unwrap_or("");
let username = headers["x-auth-user"].to_str().unwrap_or("").trim();
let password = headers["x-auth-key"].to_str().unwrap_or("");
let mut tx = db_pool.begin().await.unwrap();

View file

@ -2,7 +2,7 @@
Description=KOReader Sync Server
After=syslog.target
After=network.target
After=redis.service
After=postgresql.service
[Service]
RestartSec=2s
@ -11,7 +11,7 @@ User=myuser
Group=users
WorkingDirectory=/home/myuser
ExecStart=/usr/local/bin/kosyncrs
Environment="PG_URL=postgresql://kosync:password@localhost/kosync"
Environment=PG_URL=postgresql://kosync:password@localhost/kosync PORT=3003
Restart=always
[Install]