diff --git a/Cargo.lock b/Cargo.lock
index ac96a96a2e..7f17d70d92 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1181,7 +1181,7 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hulypulse"
-version = "0.1.8"
+version = "0.1.10"
dependencies = [
"actix",
"actix-cors",
diff --git a/Cargo.toml b/Cargo.toml
index 679318aeab..c79af425b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "hulypulse"
-version = "0.1.8"
+version = "0.1.10"
edition = "2024"
[dependencies]
diff --git a/scripts/TEST_HTTP_API.sh b/scripts/TEST_HTTP_API.sh
index 04383691a1..a07394a694 100755
--- a/scripts/TEST_HTTP_API.sh
+++ b/scripts/TEST_HTTP_API.sh
@@ -6,10 +6,28 @@ source ./pulse_lib.sh
TOKEN=$(./token.sh claims.json)
#echo ${TOKEN}
#exit
-
-
ZP="00000000-0000-0000-0000-000000000001/TESTS"
+
+
+put "00000000-0000-0000-0000-000000000001/TESTS/val1" "value" "HULY-TTL: 1"
+put "00000000-0000-0000-0000-000000000001/TESTS/val2" "value" "HULY-TTL: 12"
+put "00000000-0000-0000-0000-000000000001/TESTS/val3" "value" "HULY-TTL: 1"
+
+get "00000000-0000-0000-0000-000000000001/TESTS/"
+sleep 2
+# get "00000000-0000-0000-0000-000000000001/TESTS/val2"
+get "00000000-0000-0000-0000-000000000001/TESTS/"
+
+
+
+exit
+
+
+
+
+
+
put "00000000-0000-0000-0000-000000000001/TESTS" "Value"
#exit
diff --git a/scripts/TEST_lleo.html b/scripts/TEST_lleo.html
new file mode 100644
index 0000000000..706cc56619
--- /dev/null
+++ b/scripts/TEST_lleo.html
@@ -0,0 +1,140 @@
+
+
+
+
+ WebSocket JSON Tester
+
+
+
+
+ WebSocket JSON Tester
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Waiting for server response...
+
+
+
+
+
diff --git a/scripts/TEST_no_auth.html b/scripts/TEST_no_auth.html
new file mode 100644
index 0000000000..26b34faca7
--- /dev/null
+++ b/scripts/TEST_no_auth.html
@@ -0,0 +1,141 @@
+
+
+
+
+ WebSocket JSON Tester
+
+
+
+
+ WebSocket JSON Tester
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Waiting for server response...
+
+
+
+
+
diff --git a/scripts/lleo_TEST_HTTP_API.sh b/scripts/lleo_TEST_HTTP_API.sh
new file mode 100755
index 0000000000..a30faf5608
--- /dev/null
+++ b/scripts/lleo_TEST_HTTP_API.sh
@@ -0,0 +1,149 @@
+#!/bin/bash
+
+clear
+source ./pulse_lib_lleo.sh
+
+#TOKEN=$(./token.sh claims.json)
+#echo ${TOKEN}
+
+
+
+put "dnevnik/onlline/admin" "oki" "HULY-TTL: 3"
+
+
+
+exit
+ZP="00000000-0000-0000-0000-000000000001/TESTS"
+
+put "00000000-0000-0000-0000-000000000001/TESTS/val1" "value" "HULY-TTL: 3"
+put "00000000-0000-0000-0000-000000000001/TESTS/val2" "value" "HULY-TTL: 12"
+put "00000000-0000-0000-0000-000000000001/TESTS/val3" "value" "HULY-TTL: 3"
+
+get "00000000-0000-0000-0000-000000000001/TESTS/"
+sleep 4
+# get "00000000-0000-0000-0000-000000000001/TESTS/val2"
+get "00000000-0000-0000-0000-000000000001/TESTS/"
+
+
+
+exit
+
+
+
+
+
+
+put "00000000-0000-0000-0000-000000000001/TESTS" "Value"
+
+#exit
+ delete "00000000-0000-0000-0000-000000000001/TESTS"
+put "00000000-0000-0000-0000-000000000001/TESTS" "Value"
+ delete "00000000-0000-0000-0000-000000000001/TESTS" "If-Match: *"
+put "00000000-0000-0000-0000-000000000001/TESTS" "Value"
+ delete "00000000-0000-0000-0000-000000000001/TESTS" "If-Match: dd358c74cb9cb897424838fbcb69c933"
+
+#exit
+
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/1" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/2" "Value_2" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/2/$/secret" "Value_secret" "HULY-TTL: 2"
+ get "00000000-0000-0000-0000-000000000001/TESTS/"
+
+#exit
+
+ delete "0000000/TESTS"
+ delete ${ZP}
+ put ${ZP} "Value_1" "HULY-TTL: 2"
+ delete ${ZP}
+
+echo "--------- authorization_test ----------"
+TOKEN=""
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 2"
+TOKEN=$(./token.sh claims_system.json)
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 2"
+TOKEN=$(./token.sh claims_wrong_ws.json)
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 2"
+TOKEN=$(./token.sh claims.json)
+ put "00000000-0000-0000-0000-000000000002/TESTS" "Value_1" "HULY-TTL: 2"
+
+
+
+echo "--------- if-match ----------"
+
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/1" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/2" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/3$" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/3/secret$/4" "Value_1" "HULY-TTL: 2"
+ get "00000000-0000-0000-0000-000000000001/TESTS"
+ get "00000000-0000-0000-0000-000000000001/TESTS/"
+ get "00000000-0000-0000-0000-000000000001/TESTS/3/secret$/"
+
+
+echo "--------- Deprecated symbols ----------"
+
+ put "00000000-0000-0000-0000-000000000001/'TESTS" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TES?TS" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS*" "Value_1" "HULY-TTL: 2"
+ put "00000000-0000-0000-0000-000000000001/TESTS/" "Value_1" "HULY-TTL: 2"
+
+echo "--------- if-match ----------"
+
+ delete ${ZP}
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 1" "If-Match: *"
+ get ${ZP}
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_2" "HULY-TTL: 1"
+ get ${ZP}
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_3" "HULY-TTL: 1" "If-Match: dd358c74cb9cb897424838fbcb69c933"
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_4" "HULY-TTL: 1" "If-Match: *"
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_5" "HULY-TTL: 1" "If-Match: c7bcabf6b98a220f2f4888a18d01568d"
+ put "00000000-0000-0000-0000-000000000001/TESTS" "Value_6" "HULY-TTL: 1" "If-None-Match: *"
+
+echo "-- Expected OK: 201 Created (key was not exist)"
+
+ put ${ZP} "enother text" "If-None-Match" "*"
+
+ put ${ZP} "some text"
+ echo "-- Expected Error: 412 Precondition Failed (key was exist)"
+ put ${ZP} "enother text" "If-None-Match" "*"
+
+echo "================> UPDATE PUT If-Match"
+
+ get ${ZP}
+
+ echo "-- Expected OK: 204 No Content (right hash)"
+ put ${ZP} "some text" "If-Match" "552e21cd4cd9918678e3c1a0df491bc3"
+ get ${ZP}
+
+ echo "-- Expected OK: 204 No Content (hash still right)"
+ put ${ZP} "enother version" "If-Match" "552e21cd4cd9918678e3c1a0df491bc3"
+
+
+
+
+
+
+put "00000000-0000-0000-0000-000000000001/TESTS" "Value_1" "HULY-TTL: 3"
+echo "sleep 1 sec"
+sleep 1
+get "00000000-0000-0000-0000-000000000001/TESTS"
+echo "sleep 3 sec"
+sleep 2
+get "00000000-0000-0000-0000-000000000001/TESTS"
+
+echo "--------- delete ----------"
+put "00000000-0000-0000-0000-000000000001/TESTS" "Value_2" "HULY-TTL: 3"
+get "00000000-0000-0000-0000-000000000001/TESTS"
+delete "00000000-0000-0000-0000-000000000001/TESTS"
+get "00000000-0000-0000-0000-000000000001/TESTS"
+
+echo "--------- prefix ----------"
+put "00000000-0000-0000-0000-000000000001/TESTS1" "Value_1" "HULY-TTL: 3"
+put "00000000-0000-0000-0000-000000000001/TESTS2" "Value_1" "HULY-TTL: 3"
+put "00000000-0000-0000-0000-000000000001/HREST2" "Value_1" "HULY-TTL: 3"
+get "00000000-0000-0000-0000-000000000001?prefix=TES"
+sleep 1
+get "00000000-0000-0000-0000-000000000001?prefix="
+
+exit
diff --git a/scripts/pulse_lib_lleo.sh b/scripts/pulse_lib_lleo.sh
new file mode 100755
index 0000000000..4cf8832fca
--- /dev/null
+++ b/scripts/pulse_lib_lleo.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+clear
+
+# URL="http://localhost:8095/api"
+URL="https://hulypulse_mem.lleo.me/api"
+
+R='\033[0;31m' # Color red
+G='\033[0;32m' # Color green
+W='\033[0;33m' # Color ?
+S='\033[0;34m' # Color Blue
+F='\033[0;35m' # Color Fiolet
+L='\033[0;36m' # Color LightBlue
+N='\033[0m' # No Color
+GRAY='\033[90m' # bright black
+
+api() {
+ local tmpfile
+ tmpfile=$1
+ local status
+ status=$(head -n 1 "$tmpfile")
+ local status_code
+ status_code=$(echo "$status" | awk '{print $2}')
+ local etag
+ etag=$(grep -i "^ETag:" "${tmpfile}")
+ local body
+ body=$(awk 'found { print; next } NF == 0 { found = 1 }' "$tmpfile")
+ case "$status_code" in
+ 2*) echo -en "${G}${status}${N}" ;;
+ 3*) echo -en "${F}${status}${N}" ;;
+ 4*) echo -en "${R}${status}${N}" ;;
+ 5*) echo -en "${R}${status}${N}" ;;
+ *) echo -en "${GRAY}${status}${N}" ;;
+ esac
+ if [ -n "$etag" ]; then echo -n -e " ${F}${etag}${N}" ; fi
+
+ body=$(echo "$body" | sed 's/{/\\n{/g')
+
+ if [ -n "$body" ]; then echo -e "\n ${GRAY}[${body}]${N}" ; else echo -e " ${L}(no body)${N}" ; fi
+ rm -f "$tmpfile"
+}
+
+get() {
+ echo -n -e "📥 ${L}GET ${W}$1${N} > "
+ local tmpfile
+ tmpfile=$(mktemp)
+ curl -i -s -X GET "$URL/$1" -H "Authorization: Bearer ${TOKEN}" | tr -d '\r' > "$tmpfile"
+ api ${tmpfile}
+}
+
+put() { # If-None-Match If-Match
+ local match
+ local match_prn
+# if [ -n "$3" ]; then match=(-H "$3: $4") ; else match=() ; fi
+# if [ -n "$3" ]; then match_prn=" ${F}$3:$4${N}" ; else match_prn="" ; fi
+# echo -n -e "📥 ${L}PUT ${W}$1${N}${match_prn} > "
+
+ if [ -n "$3" ]; then match1=(-H "$3") ; else match1=() ; fi
+ if [ -n "$3" ]; then match1_prn=" ${F}$3${N}" ; else match1_prn="" ; fi
+ if [ -n "$4" ]; then match2=(-H "$4") ; else match2=() ; fi
+ if [ -n "$4" ]; then match2_prn=" ${F}$4${N}" ; else match2_prn="" ; fi
+ echo -n -e "📥 ${L}PUT ${W}$1${N}${match1_prn}${match2_prn} > "
+
+ local tmpfile
+ tmpfile=$(mktemp)
+# curl -v -i -s -X PUT "$URL/$1" "${match1[@]}" "${match2[@]}" -H "Content-Type: application/json" -d "$2" | tr -d '\r' > "$tmpfile"
+# curl -v -i -s -X PUT "$URL/$1" -H "Authorization: Bearer ${TOKEN}" "${match1[@]}" "${match2[@]}" -H "Content-Type: application/json" -d "$2" | tr -d '\r' > "$tmpfile"
+ curl -i -s -X PUT "$URL/$1" -H "Authorization: Bearer ${TOKEN}" "${match1[@]}" "${match2[@]}" -H "Content-Type: application/json" -d "$2" | tr -d '\r' > "$tmpfile"
+ api ${tmpfile}
+}
+
+delete() {
+ echo -n -e "📥 ${L}DELETE ${W}$1${N} > "
+ local tmpfile
+ tmpfile=$(mktemp)
+ curl -i -s -X DELETE "$URL/$1" -H "Authorization: Bearer ${TOKEN}" | tr -d '\r' > "$tmpfile"
+# curl -v -i -s -X DELETE "$URL/$1" -H "Authorization: Bearer ${TOKEN}" | tr -d '\r' > "$tmpfile"
+ api ${tmpfile}
+}
diff --git a/src/config.rs b/src/config.rs
index dfe5037cba..feea94aa94 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -46,6 +46,9 @@ pub struct Config {
pub redis_service: String,
pub max_ttl: usize,
+
+ pub memory_mode: Option,
+ pub no_authorization: Option,
}
pub static CONFIG: LazyLock = LazyLock::new(|| {
diff --git a/src/config/default.toml b/src/config/default.toml
index a570fff0c7..b4ad885aed 100644
--- a/src/config/default.toml
+++ b/src/config/default.toml
@@ -9,3 +9,6 @@ redis_mode = "direct"
redis_service = "mymaster"
max_ttl = 3600
+
+memory_mode = true
+no_authorization = true
\ No newline at end of file
diff --git a/src/db.rs b/src/db.rs
new file mode 100644
index 0000000000..71f84a2bc4
--- /dev/null
+++ b/src/db.rs
@@ -0,0 +1,101 @@
+use std::sync::Arc;
+
+use crate::{
+ hub_service::{broadcast_event, HubState, RedisEvent, RedisEventAction},
+ memory::{memory_delete, memory_list, memory_read, memory_save, MemoryBackend},
+ redis::{redis_delete, redis_list, redis_read, redis_save, RedisArray, SaveMode, Ttl}
+};
+use ::redis::aio::MultiplexedConnection;
+use tokio::sync::RwLock;
+
+#[derive(Clone)]
+pub struct Db {
+ inner: DbInner,
+ hub: Arc>,
+}
+
+#[derive(Clone)]
+enum DbInner {
+ Memory(MemoryBackend),
+ Redis(MultiplexedConnection),
+}
+
+impl Db {
+
+ pub fn new_memory(m: MemoryBackend, hub: Arc>) -> Self {
+ Self { inner: DbInner::Memory(m), hub }
+ }
+ pub fn new_redis(c: MultiplexedConnection, hub: Arc>) -> Self {
+ Self { inner: DbInner::Redis(c), hub }
+ }
+
+
+ pub async fn list(&self, key: &str) -> redis::RedisResult> {
+ match &self.inner {
+ DbInner::Memory(m) => memory_list(m, key).await,
+ DbInner::Redis(conn) => {
+ let mut c = conn.clone();
+ redis_list(&mut c, key).await
+ }
+ }
+ }
+
+ pub async fn read(&self, key: &str) -> redis::RedisResult