diff --git a/build/docker-compose.local.yml b/build/docker-compose.local.yml new file mode 100644 index 0000000..f96e03e --- /dev/null +++ b/build/docker-compose.local.yml @@ -0,0 +1,115 @@ +services: + db: + image: postgres:18 + container_name: db + restart: always + env_file: + - ./env/db.env + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + start_period: 30s + volumes: + - pgdata:/var/postgresql/data + + kafdrop: + image: obsidiandynamics/kafdrop + restart: "no" + ports: + - "127.0.0.1:9000:9000" + env_file: + - ./env/kafdrop.env + depends_on: + - "kafka" + kafka: + image: apache/kafka:3.9.0 + restart: "no" + ports: + - "127.0.0.1:9092:9092" + - "127.0.0.1:9093:9093" + env_file: + - ./env/kafka.env + healthcheck: + test: ["CMD-SHELL", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server 127.0.0.1:9092 --list"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 20s + volumes: + - kafkadata:/var/lib/kafka/data + + kafka-init: + image: apache/kafka:3.9.0 + command: [ "sh", "-c", "ls -l /tmp/create_topic.sh && /tmp/create_topic.sh" ] + depends_on: + kafka: + condition: service_healthy + volumes: + - ./init-scripts/create_topic.sh:/tmp/create_topic.sh + env_file: + - ./env/kafka-init.env + + valkey: + image: valkey/valkey:9.0.0 + container_name: valkey + ports: + - "127.0.0.1:6379:6379" + + presense-decoder: + image: presense-decoder + container_name: presense-decoder + env_file: + - ./env/presense-decoder.env + depends_on: + kafka-init: + condition: service_completed_successfully + db: + condition: service_healthy + restart: always + + presense-server: + image: presense-server + container_name: presense-server + env_file: + - ./env/presense-server.env + ports: + - "127.0.0.1:1902:1902" + depends_on: + valkey: + condition: service_started + kafka-init: + condition: service_completed_successfully + db: + condition: service_healthy + restart: always + + presense-bridge: + image: presense-bridge + container_name: presense-bridge + env_file: + - ./env/presense-bridge.env + depends_on: + kafka-init: + condition: service_completed_successfully + db: + condition: service_healthy + restart: always + + presense-location: + image: presense-location + container_name: presense-location + env_file: + - ./env/presense-location.env + depends_on: + kafka-init: + condition: service_completed_successfully + db: + condition: service_healthy + restart: always + + +volumes: + pgdata: + kafkadata: diff --git a/build/init-scripts/create_topic.sh b/build/init-scripts/create_topic.sh index 44a07ae..ae752bf 100755 --- a/build/init-scripts/create_topic.sh +++ b/build/init-scripts/create_topic.sh @@ -1,48 +1,90 @@ #!/bin/bash +set -euo pipefail + # Retention: messages older than 2 days are deleted (172800000 ms = 2 days) RETENTION_MS=172800000 +KAFKA_BOOTSTRAP_SERVER="kafka:29092" + +wait_for_topic() { + local topic="$1" + # Topic metadata can take a moment to become available after creation. + for i in $(seq 1 30); do + if /opt/kafka/bin/kafka-topics.sh \ + --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ + --topic "$topic" \ + --describe >/dev/null 2>&1; then + return 0 + fi + sleep 1 + done + echo "timed out waiting for topic '$topic' to be available" >&2 + return 1 +} + # create topic rawbeacons -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic rawbeacons \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic apibeacons -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic apibeacons \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic alertBeacons -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic alertbeacons \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic locevents -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic locevents \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic settings -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic settings \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic alert -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic alert \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic healthlocation -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic healthlocation \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic healthdecoder -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic healthdecoder \ --partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS # create topic healthbridge -/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:29092 \ +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ --create --if-not-exists --topic healthbridge \ ---partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS \ No newline at end of file +--partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS + +# create topic parser (server writes parser config, decoder reads it) +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ +--create --if-not-exists --topic parser \ +--partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS + +# create topic mqtt (bridge reads/writes MQTT event payloads) +/opt/kafka/bin/kafka-topics.sh --bootstrap-server "$KAFKA_BOOTSTRAP_SERVER" \ +--create --if-not-exists --topic mqtt \ +--partitions 1 --replication-factor 1 --config retention.ms=$RETENTION_MS + +wait_for_topic rawbeacons +wait_for_topic apibeacons +wait_for_topic alertbeacons +wait_for_topic locevents +wait_for_topic settings +wait_for_topic alert +wait_for_topic healthlocation +wait_for_topic healthdecoder +wait_for_topic healthbridge +wait_for_topic parser +wait_for_topic mqtt \ No newline at end of file diff --git a/internal/pkg/apiclient/auth.go b/internal/pkg/apiclient/auth.go index e74e8f5..097d385 100644 --- a/internal/pkg/apiclient/auth.go +++ b/internal/pkg/apiclient/auth.go @@ -23,6 +23,8 @@ func GetToken(ctx context.Context, cfg *config.Config, client *http.Client) (str formData.Set("username", cfg.HTTPUsername) formData.Set("password", cfg.HTTPPassword) formData.Set("audience", cfg.HTTPAudience) + fmt.Printf("formData: %+v\n", formData) + fmt.Printf("cfg.APIAuthURL: %+v\n", cfg.APIAuthURL) req, err := http.NewRequest("POST", fmt.Sprintf("%s/realms/API.Server.local/protocol/openid-connect/token", cfg.APIAuthURL), strings.NewReader(formData.Encode())) if err != nil { diff --git a/scripts/api-test.sh b/scripts/api-test.sh new file mode 100755 index 0000000..c6f717a --- /dev/null +++ b/scripts/api-test.sh @@ -0,0 +1,246 @@ +BASE_URL="http://localhost:1902" + +echo "==========================================" +echo "GATEWAY API TESTS" +echo "==========================================" + +echo "1. Listing all Gateways" +LIST=$(curl -s -X GET "$BASE_URL/reslevis/getGateways" | jq -c '.[]') +GATEWAY_IDS=() + +IFS=$'\n' +for r in $LIST +do + echo "$r" + GATEWAY_IDS+=($(echo "$r" | jq -r '.id')) +done + +sleep 1 + +if [ ${#GATEWAY_IDS[@]} -gt 1 ]; then + echo -e "\n\n2. Updating Gateway ${GATEWAY_IDS[1]}" + curl -X PUT "$BASE_URL/reslevis/updateGateway/${GATEWAY_IDS[1]}" \ + -H "Content-Type: application/json" \ + -d "{ + \"id\": \"${GATEWAY_IDS[1]}\", + \"name\": \"GU-100-Updated\", + \"mac\": \"AA:BB:CC:DD:EE:FF\", + \"status\": \"online\", + \"model\": \"MG3\", + \"ip\": \"127.0.0.1\", + \"position\": \"unknown\", + \"x\": 1, + \"y\": 1, + \"notes\": \"some description\", + \"floor\": \"second\", + \"building\": \"hospital\" + }" + + sleep 1 + + echo -e "\n\n3. Listing Gateways after update" + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getGateways" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done + + sleep 1 + + echo -e "\n\n4. Deleting Gateway ${GATEWAY_IDS[1]}" + curl -X DELETE "$BASE_URL/reslevis/removeGateway/${GATEWAY_IDS[1]}" + + sleep 1 + + echo -e "\n\n5. Verifying Delete (List again)..." + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getGateways" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done +else + echo "Not enough gateways to test update/delete" +fi + + +echo -e "\n\n==========================================" +echo "ZONE API TESTS" +echo "==========================================" + +echo "6. Listing all Zones" +LIST=$(curl -s -X GET "$BASE_URL/reslevis/getZones" | jq -c '.[]') +ZONE_IDS=() + +IFS=$'\n' +for r in $LIST +do + echo "$r" + ZONE_IDS+=($(echo "$r" | jq -r '.id')) +done + +sleep 1 + +if [ ${#ZONE_IDS[@]} -gt 0 ]; then + echo -e "\n\n7. Updating Zone ${ZONE_IDS[0]}" + curl -X PUT "$BASE_URL/reslevis/updateZone" \ + -H "Content-Type: application/json" \ + -d "{ + \"id\": \"${ZONE_IDS[0]}\", + \"name\": \"Zone-Updated\", + \"groups\": [\"security\", \"logistics\"] + }" + + sleep 1 + + echo -e "\n\n8. Listing Zones after update" + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getZones" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done + + sleep 1 + + echo -e "\n\n9. Deleting Zone ${ZONE_IDS[0]}" + curl -X DELETE "$BASE_URL/reslevis/removeZone/${ZONE_IDS[0]}" + + sleep 1 + + echo -e "\n\n10. Verifying Delete (List again)..." + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getZones" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done +else + echo "No zones to test update/delete" +fi + + +echo -e "\n\n==========================================" +echo "TRACKERZONE API TESTS" +echo "==========================================" + +echo "11. Listing all TrackerZones" +LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackerZones" | jq -c '.[]') +TRACKERZONE_IDS=() + +IFS=$'\n' +for r in $LIST +do + echo "$r" + TRACKERZONE_IDS+=($(echo "$r" | jq -r '.id')) +done + +sleep 1 + +if [ ${#TRACKERZONE_IDS[@]} -gt 0 ]; then + echo -e "\n\n12. Updating TrackerZone ${TRACKERZONE_IDS[0]}" + curl -X PUT "$BASE_URL/reslevis/updateTrackerZone" \ + -H "Content-Type: application/json" \ + -d "{ + \"id\": \"${TRACKERZONE_IDS[0]}\", + \"name\": \"TrackerZone-Updated\" + }" + + sleep 1 + + echo -e "\n\n13. Listing TrackerZones after update" + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackerZones" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done + + sleep 1 + + echo -e "\n\n14. Deleting TrackerZone ${TRACKERZONE_IDS[0]}" + curl -X DELETE "$BASE_URL/reslevis/removeTrackerZone/${TRACKERZONE_IDS[0]}" + + sleep 1 + + echo -e "\n\n15. Verifying Delete (List again)..." + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackerZones" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done +else + echo "No trackerzones to test update/delete" +fi + + +echo -e "\n\n==========================================" +echo "TRACKER API TESTS" +echo "==========================================" + +echo "16. Listing all Trackers" +LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackers" | jq -c '.[]') +TRACKER_IDS=() + +IFS=$'\n' +for r in $LIST +do + echo "$r" + TRACKER_IDS+=($(echo "$r" | jq -r '.id')) +done + +sleep 1 + +if [ ${#TRACKER_IDS[@]} -gt 0 ]; then + echo -e "\n\n17. Updating Tracker ${TRACKER_IDS[0]}" + curl -X PUT "$BASE_URL/reslevis/updateTracker" \ + -H "Content-Type: application/json" \ + -d "{ + \"id\": \"${TRACKER_IDS[0]}\", + \"name\": \"Tracker-Updated\", + \"battery\": 85, + \"status\": \"inactive\" + }" + + sleep 1 + + echo -e "\n\n18. Listing Trackers after update" + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackers" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done + + sleep 1 + + echo -e "\n\n19. Deleting Tracker ${TRACKER_IDS[0]}" + curl -X DELETE "$BASE_URL/reslevis/removeTracker/${TRACKER_IDS[0]}" + + sleep 1 + + echo -e "\n\n20. Verifying Delete (List again)..." + LIST=$(curl -s -X GET "$BASE_URL/reslevis/getTrackers" | jq -c '.[]') + + IFS=$'\n' + for r in $LIST + do + echo "$r" + done +else + echo "No trackers to test update/delete" +fi + + +echo -e "\n\n==========================================" +echo "ALL TESTS COMPLETED" +echo "==========================================" diff --git a/scripts/build/only_build.sh b/scripts/build/only_build.sh new file mode 100755 index 0000000..072002e --- /dev/null +++ b/scripts/build/only_build.sh @@ -0,0 +1,10 @@ +docker build -t presense-server -f ../../build/package/Dockerfile.server ../../ +ΒΈ +# Build the location +docker build -t presense-location -f ../../build/package/Dockerfile.location ../../ + +# Build the decoder +docker build -t presense-decoder -f ../../build/package/Dockerfile.decoder ../../ + +# Build the bridge +docker build -t presense-bridge -f ../../build/package/Dockerfile.bridge ../../ \ No newline at end of file diff --git a/scripts/testAPI2.sh b/scripts/testAPI2.sh new file mode 100755 index 0000000..254d133 --- /dev/null +++ b/scripts/testAPI2.sh @@ -0,0 +1,21 @@ +#!/bin/bash +URL="http://127.0.0.1:1902/api/beacons" +BEACON_ID="C300003947C4" + +echo "POST (create)" +curl -s -X POST $URL \ + -H "Content-Type: application/json" \ + -d '{"Beacon_id":"'"$BEACON_ID"'","Name":"Beacon1","tx_power":-59,"rssi":-70}' +echo -e "\n" + +sleep 1 + +echo "GET (list after update)" +curl -s -X GET $URL +echo -e "\n" + +sleep 1 + +echo "GET (list after update)" +curl -s -X GET $URL +echo -e "\n" diff --git a/scripts/zones.sh b/scripts/zones.sh new file mode 100755 index 0000000..dcea546 --- /dev/null +++ b/scripts/zones.sh @@ -0,0 +1,46 @@ +#!/bin/bash +BASE_URL="http://localhost:1902" + +echo "1. Adding Tracker Zone Mapping..." +curl -X POST "$BASE_URL/reslevis/postTrackerZone" \ +-H "Content-Type: application/json" \ +-d '{ + "id": "b6b2a2e4-58b3-4aa4-8d6a-4b55a2c5b2d3", + "zoneList": ["0c7b9c7f-6d0f-4d4e-9e4a-2c9f2b1d6a11","1d2e3f40-1111-2222-3333-444455556666"], + "tracker": "1e93b3fd-7d67-4a53-9c7a-0f0a8e7e41c6", + "days": "All,Mon,Tue,Wed,Thu,Fri", + "time": "09:00-17:00" +}' + +sleep 1 + +echo -e "\n\n2. Listing Trackers..." +curl -X GET "$BASE_URL/reslevis/getTrackerZones" + +# sleep 1 + +# echo "Updating Tracker Zone List and Time..." +# curl -X PUT "$BASE_URL/reslevis/updateTrackerZone" \ +# -H "Content-Type: application/json" \ +# -d '{ +# "id": "tz_001", +# "zoneList": ["zone_C"], +# "tracker": "TAG_55", +# "days": "Sat-Sun", +# "time": "10:00-14:00" +# }' + +# sleep 1 + +# echo -e "\n\n2. Listing Trackers..." +# curl -X GET "$BASE_URL/reslevis/getTrackerZones" + +# sleep 1 + +# echo -e "\n\n3. Deleting Tracker Mapping..." +# curl -X DELETE "$BASE_URL/reslevis/removeTrackerZone/tz_001" + +# sleep 1 + +# echo -e "\n\n2. Listing Trackers..." +# curl -X GET "$BASE_URL/reslevis/getTrackerZones"