| @@ -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: | |||
| @@ -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 | |||
| --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 | |||
| @@ -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 { | |||
| @@ -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 "==========================================" | |||
| @@ -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 ../../ | |||
| @@ -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" | |||
| @@ -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" | |||