diff --git a/go-socket b/go-socket index c3928b6..620c085 100755 Binary files a/go-socket and b/go-socket differ diff --git a/http.go b/http.go index 67ab799..52cd5f0 100644 --- a/http.go +++ b/http.go @@ -87,7 +87,7 @@ func HttpHandleNewUser(response http.ResponseWriter, request *http.Request) { } } -func HttpHandleLogin(response http.ResponseWriter, request *http.Request) { +func HttpHandleNewToken(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } @@ -144,7 +144,7 @@ func HttpHandleLogin(response http.ResponseWriter, request *http.Request) { } } -func HttpHandleGroupCreate(response http.ResponseWriter, request *http.Request) { +func HttpHandeNewGroup(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } @@ -208,7 +208,11 @@ func HttpHandleGroupCreate(response http.ResponseWriter, request *http.Request) binary.BigEndian.PutUint32(groupIdBytes, group.Id) response.WriteHeader(http.StatusCreated) - response.Write(groupIdBytes) + _, err = response.Write(groupIdBytes) + if err != nil { + http.Error(response, "internal server error", http.StatusInternalServerError) + return + } } func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Request) { @@ -288,3 +292,27 @@ func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Reques return } } + +func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) { + token := request.FormValue("token") + if token == "" { + http.Error(response, "invalid token", http.StatusUnauthorized) + } + + subject := request.FormValue("subject") + if subject == "" { + http.Error(response, "invalid subject", http.StatusBadRequest) + } + + content := request.FormValue("content") + if content == "" { + http.Error(response, "invalid content", http.StatusBadRequest) + } + + clientId, err := TokenValidateGetId(token) + if err != nil { + http.Error(response, "invalid token", http.StatusUnauthorized) + } + + +} diff --git a/main.go b/main.go index e9c1b29..f2921cb 100644 --- a/main.go +++ b/main.go @@ -18,8 +18,8 @@ func main() { DbInit(ctx) http.HandleFunc("/new/client", withCORS(HttpHandleNewUser)) - http.HandleFunc("/new/token", withCORS(HttpHandleLogin)) - http.HandleFunc("/new/group", withCORS(HttpHandleGroupCreate)) + http.HandleFunc("/new/token", withCORS(HttpHandleNewToken)) + http.HandleFunc("/new/group", withCORS(HttpHandeNewGroup)) http.HandleFunc("/mod/group/addclients", withCORS(HttpHandleGroupAddClient)) http.HandleFunc("/ws", ServeWsConnection) diff --git a/tests/.state b/tests/.state index c9eb8ef..f099442 100644 --- a/tests/.state +++ b/tests/.state @@ -1,5 +1,5 @@ -TOKEN1=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzc0ODYzMTYxLCJpYXQiOjE3NzQ4NTk1NjF9.Xc2AdvB-OppMH_Xbudlf7roy81mLJW_OkZwriVP6tck +TOKEN1=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzc0ODY2MjE2LCJpYXQiOjE3NzQ4NjI2MTZ9.hxU-qpJ1Grz4yglr5TD_7ik5cIOU7_fkaIskoNdML0I USER1_ID=1 -TOKEN2=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyIiwiZXhwIjoxNzc0ODYzMTYxLCJpYXQiOjE3NzQ4NTk1NjF9.EOY84pt8UUrIsGWAVgVUDUJdGxdll6Db-lFFKw4HeA4 +TOKEN2=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyIiwiZXhwIjoxNzc0ODY2MjE3LCJpYXQiOjE3NzQ4NjI2MTd9.trOFcMUeFNrR2H9VlaM9vDYaupZq_ysGzCb1iz3Gxc0 USER2_ID=2 GROUP_ID=1 diff --git a/tests/05_send_message.sh b/tests/05_send_message.sh index 283ce3e..091ad5e 100755 --- a/tests/05_send_message.sh +++ b/tests/05_send_message.sh @@ -1,68 +1,78 @@ #!/bin/bash -# Send a message on the group via WebSocket (requires websocat) +# Send message from user_one to the group, verify user_two receives it source "$(dirname "$0")/config.sh" TOKEN1=$(load_state "TOKEN1") +TOKEN2=$(load_state "TOKEN2") GROUP_ID=$(load_state "GROUP_ID") -echo "=== Debug: loaded state ===" -echo " TOKEN1: ${TOKEN1:0:20}..." -echo " GROUP_ID: $GROUP_ID" - -if [[ -z "$TOKEN1" || -z "$GROUP_ID" ]]; then +if [[ -z "$TOKEN1" || -z "$TOKEN2" || -z "$GROUP_ID" ]]; then echo "ERROR: Missing state. Run previous scripts first." + echo " TOKEN1=$TOKEN1" + echo " TOKEN2=$TOKEN2" + echo " GROUP_ID=$GROUP_ID" exit 1 fi -if ! command -v websocat &>/dev/null; then - echo "ERROR: websocat is not installed." - echo "Install it with: cargo install websocat" - echo " or: pacman -S websocat" +MESSAGE="Hello from user_one!" + +echo "=== Sending message from user_one to group $GROUP_ID ===" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +echo "[DEBUG] tmpdir: $TMPDIR" +echo "[DEBUG] TOKEN1: ${TOKEN1:0:20}..." +echo "[DEBUG] TOKEN2: ${TOKEN2:0:20}..." +echo "[DEBUG] GROUP_ID: $GROUP_ID" + +# Receiver (user_two): authenticate then wait for messages +echo "[DEBUG] starting receiver (user_two)..." +{ echo '{"token":"'"$TOKEN2"'"}'; sleep 5; } \ + | stdbuf -oL websocat ws://localhost:8080/ws > "$TMPDIR/received" 2>"$TMPDIR/recv_err" & +RECV_PID=$! +echo "[DEBUG] receiver PID: $RECV_PID" +sleep 0.5 + +# Sender (user_one): authenticate, send message +SEND_PAYLOAD='{"subject":'"$GROUP_ID"',"content":"'"$MESSAGE"'"}' +echo "[DEBUG] starting sender (user_one)..." +echo "[DEBUG] send payload: $SEND_PAYLOAD" +{ echo '{"token":"'"$TOKEN1"'"}'; sleep 0.5; echo "$SEND_PAYLOAD"; sleep 0.5; } \ + | websocat ws://localhost:8080/ws > "$TMPDIR/send_out" 2>"$TMPDIR/send_err" & +SEND_PID=$! +echo "[DEBUG] sender PID: $SEND_PID" + +echo "[DEBUG] waiting 2s for message delivery..." +sleep 2 + +echo "[DEBUG] killing connections..." +kill $RECV_PID $SEND_PID 2>/dev/null +wait $RECV_PID 2>/dev/null +RECV_EXIT=$? +wait $SEND_PID 2>/dev/null +SEND_EXIT=$? +echo "[DEBUG] receiver exit: $RECV_EXIT, sender exit: $SEND_EXIT" + +RECV_ERR=$(cat "$TMPDIR/recv_err") +SEND_ERR=$(cat "$TMPDIR/send_err") +SEND_OUT=$(cat "$TMPDIR/send_out") +[[ -n "$RECV_ERR" ]] && echo "[DEBUG] receiver stderr: $RECV_ERR" +[[ -n "$SEND_ERR" ]] && echo "[DEBUG] sender stderr: $SEND_ERR" +[[ -n "$SEND_OUT" ]] && echo "[DEBUG] sender received: $SEND_OUT" + +RESPONSE=$(cat "$TMPDIR/received") +echo "user_two received: $RESPONSE" + +if [[ -z "$RESPONSE" ]]; then + echo "[DEBUG] EMPTY response - no data received by user_two" + echo "FAIL: message not received" exit 1 fi -AUTH_MSG="{\"token\":\"$TOKEN1\"}" -CHAT_MSG="{\"subject\":$GROUP_ID,\"content\":\"Hello from user1!\"}" - -echo "" -echo "=== Sending message to group $GROUP_ID as user1 ===" -echo " Auth payload: $AUTH_MSG" -echo " Chat payload: $CHAT_MSG" -echo "" - -echo "[*] Connecting to ws://localhost:8080/ws ..." - -# Use a temp file to capture all ws output -WS_OUT=$(mktemp) -trap "rm -f $WS_OUT" EXIT - -( - echo "[>] Sending auth message..." >&2 - echo "$AUTH_MSG" - sleep 2 - echo "[>] Auth sent. Sending chat message..." >&2 - echo "$CHAT_MSG" - sleep 2 - echo "[>] Chat message sent. Closing..." >&2 -) | websocat -v ws://localhost:8080/ws 2>&1 | tee "$WS_OUT" & - -WS_PID=$! - -# Wait for websocat to finish or timeout after 10s -WAITED=0 -while kill -0 $WS_PID 2>/dev/null && [[ $WAITED -lt 10 ]]; do - sleep 1 - WAITED=$((WAITED + 1)) -done - -if kill -0 $WS_PID 2>/dev/null; then - echo "[!] websocat still running after ${WAITED}s, killing..." - kill $WS_PID 2>/dev/null - wait $WS_PID 2>/dev/null +if echo "$RESPONSE" | grep -q "$MESSAGE"; then + echo "PASS" +else + echo "FAIL: message not received" + exit 1 fi - -echo "" -echo "=== WebSocket output ===" -cat "$WS_OUT" -echo "" -echo "=== Done ===" diff --git a/tests/06_send_message_reverse.sh b/tests/06_send_message_reverse.sh new file mode 100755 index 0000000..de55cfa --- /dev/null +++ b/tests/06_send_message_reverse.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# Send message from user_two to the group, verify user_one receives it +source "$(dirname "$0")/config.sh" + +TOKEN1=$(load_state "TOKEN1") +TOKEN2=$(load_state "TOKEN2") +GROUP_ID=$(load_state "GROUP_ID") + +if [[ -z "$TOKEN1" || -z "$TOKEN2" || -z "$GROUP_ID" ]]; then + echo "ERROR: Missing state. Run previous scripts first." + echo " TOKEN1=$TOKEN1" + echo " TOKEN2=$TOKEN2" + echo " GROUP_ID=$GROUP_ID" + exit 1 +fi + +MESSAGE="Hello from user_two!" + +echo "=== Sending message from user_two to group $GROUP_ID ===" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +echo "[DEBUG] tmpdir: $TMPDIR" +echo "[DEBUG] TOKEN1: ${TOKEN1:0:20}..." +echo "[DEBUG] TOKEN2: ${TOKEN2:0:20}..." +echo "[DEBUG] GROUP_ID: $GROUP_ID" + +# Receiver (user_one): authenticate then wait for messages +echo "[DEBUG] starting receiver (user_one)..." +{ echo '{"token":"'"$TOKEN1"'"}'; sleep 5; } \ + | stdbuf -oL websocat ws://localhost:8080/ws > "$TMPDIR/received" 2>"$TMPDIR/recv_err" & +RECV_PID=$! +echo "[DEBUG] receiver PID: $RECV_PID" +sleep 0.5 + +# Sender (user_two): authenticate, send message +SEND_PAYLOAD='{"subject":'"$GROUP_ID"',"content":"'"$MESSAGE"'"}' +echo "[DEBUG] starting sender (user_two)..." +echo "[DEBUG] send payload: $SEND_PAYLOAD" +{ echo '{"token":"'"$TOKEN2"'"}'; sleep 0.5; echo "$SEND_PAYLOAD"; sleep 0.5; } \ + | websocat ws://localhost:8080/ws > "$TMPDIR/send_out" 2>"$TMPDIR/send_err" & +SEND_PID=$! +echo "[DEBUG] sender PID: $SEND_PID" + +echo "[DEBUG] waiting 2s for message delivery..." +sleep 2 + +echo "[DEBUG] killing connections..." +kill $RECV_PID $SEND_PID 2>/dev/null +wait $RECV_PID 2>/dev/null +RECV_EXIT=$? +wait $SEND_PID 2>/dev/null +SEND_EXIT=$? +echo "[DEBUG] receiver exit: $RECV_EXIT, sender exit: $SEND_EXIT" + +RECV_ERR=$(cat "$TMPDIR/recv_err") +SEND_ERR=$(cat "$TMPDIR/send_err") +SEND_OUT=$(cat "$TMPDIR/send_out") +[[ -n "$RECV_ERR" ]] && echo "[DEBUG] receiver stderr: $RECV_ERR" +[[ -n "$SEND_ERR" ]] && echo "[DEBUG] sender stderr: $SEND_ERR" +[[ -n "$SEND_OUT" ]] && echo "[DEBUG] sender received: $SEND_OUT" + +RESPONSE=$(cat "$TMPDIR/received") +echo "user_one received: $RESPONSE" + +if [[ -z "$RESPONSE" ]]; then + echo "[DEBUG] EMPTY response - no data received by user_one" + echo "FAIL: message not received" + exit 1 +fi + +if echo "$RESPONSE" | grep -q "$MESSAGE"; then + echo "PASS" +else + echo "FAIL: message not received" + exit 1 +fi diff --git a/tests/run_all.sh b/tests/run_all.sh index cddf3dd..6271f23 100755 --- a/tests/run_all.sh +++ b/tests/run_all.sh @@ -37,6 +37,12 @@ echo "=============================" bash "$DIR/05_send_message.sh" echo "" +echo "=============================" +echo " Step 6: Send message reverse" +echo "=============================" +bash "$DIR/06_send_message_reverse.sh" +echo "" + echo "=============================" echo " Cleanup" echo "=============================" diff --git a/wsServer.go b/wsServer.go index 72dd064..a4c6e9a 100644 --- a/wsServer.go +++ b/wsServer.go @@ -78,13 +78,15 @@ func sendToAllMessageCloseIfTimeout(message *map[string]any) { } func handleAuthenticatedMessage(client *Client, clientMessage *map[string]any) bool { - subject, ok := (*clientMessage)["subject"].(uint32) + subjectFlt, ok := (*clientMessage)["subject"].(float64) + subject := uint32(subjectFlt) if !ok { var msg = map[string]any{ "from": "server", "error": "subject invalid", } sendMessageCloseIfTimeout(client, &msg) + return true } content, ok := (*clientMessage)["content"].(string) @@ -94,6 +96,7 @@ func handleAuthenticatedMessage(client *Client, clientMessage *map[string]any) b "error": "content invalid", } sendMessageCloseIfTimeout(client, &msg) + return true } group, err := CacheGetGroup(subject) @@ -103,23 +106,29 @@ func handleAuthenticatedMessage(client *Client, clientMessage *map[string]any) b "error": "subject invalid", } sendMessageCloseIfTimeout(client, &msg) + return true } - for groupClientId, _ := range group.Clients { + for groupClientId := range group.Clients { + groupClient, err := CacheGetClientById(groupClientId) + if err != nil || groupClient.Id == client.Id { + continue + } + var msg = map[string]any{ "from": "group", "group": group.Id, "sender": client.Name, "content": content, } - - var groupClient *Client - groupClient, err = CacheGetClientById(groupClientId) - if err != nil { - sendMessageCloseIfTimeout(groupClient, &msg) - } + sendMessageCloseIfTimeout(groupClient, &msg) } + var msg = map[string]any{ + "from": "server", + } + sendMessageCloseIfTimeout(client) + return true }