angularazure-web-pubsub

Azure webpubsub service receive message from admin to student vs student to admin using Angular


In Angular, I'm creating an Azure Web PubSub chat application where an admin can send messages to a student, and the student can send messages to the admin.

Admin to student: const apiUrl = ${environment.Negotiate_apiBaseUrl}/${constant.NEGOTIAGE}?userid=${studentId_Admin}; student to Admin: const apiUrl = ${environment.Negotiate_apiBaseUrl}/${constant.NEGOTIAGE}?userid=${studentId};

Groups are being created on the backend, and the issue is that messages aren't being received either from the admin to the student or from the student to the admin, despite the connection being successfully established on both sides.

Am I missing something? I noticed that the await this.client.on("server-message", (e) => { ... }); is not always being invoked. Please review the script below and let me know if anything is incorrect.

WebPubSubService.ts

import { WebPubSubClient, WebPubSubClientCredential } from '@azure/web-pubsub-client';
import { HttpClient } from '@angular/common/http'; 
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class WebPubSubService {
  private client!: WebPubSubClient;
  public isConnected = false;
  constructor(private http: HttpClient) {}
 
  // Initialize WebSocket connection for student
  async initializePatientWebSocket(studentId: string) {
    try {
        const apiUrl = `${environment.Negotiate_apiBaseUrl}/${constant.NEGOTIAGE}?userid=${studentId}`;
        const response: any = await this.http.get(apiUrl).toPromise(); 
        console.log(response)
        const clientAccessUrl = response?.url;
        if (!clientAccessUrl) {
            throw new Error('clientAccessUrl is undefined');
        }

        this.client = new WebPubSubClient({
            getClientAccessUrl: clientAccessUrl,
          } as WebPubSubClientCredential);

        this.client.on("connected", (e) => {
            console.log(`Connected: ${e.connectionId}.`);
        }); 

        // Listen for messages from patients 
        await this.client.on("server-message", (e) => {
            console.log("Received message", e)
            if (e.message.data instanceof ArrayBuffer) {
                console.log(`Received message ${Buffer.from(e.message.dataType).toString("base64")}`);
            } else {
                console.log(`Received message ${JSON.stringify(e.message.data)}`);
            }
        });

        await this.client.start();
        this.isConnected = true;
        console.log('admin WebSocket connection established');
 
    } catch (error) {
        console.error('Error initializing WebSocket for admin:', error);
    }
  }

  isWebSocketConnected(): boolean {
        return this.isConnected;
  }
  // Send message to a admin
  async sendMessageToAdmin(studentId: string, message: string) {
        if (!this.isConnected || !this.client) {
            console.error('WebSocket client is not connected. Cannot send message.');
            return;
        }

        try {
            // Send the message event to the server  
                await this.client.sendEvent('message', {
                    messageText: "test message from student"
                }, 'json');
                
            console.log(`Message sent to admin ${studentId}: ${message}`);
        } catch (error) {
            console.error('Error sending message to admin:', error);
        }
    } 
}

Similarly implemented Student to Admin file as mentioned below other end to establish chat feature. Chat message both end not receiving...


Solution

  • I have tried your code but faced the same error.

    Refer this doc for using userid in Azure Web PubSub…

    
    await serviceClient.sendToAll({ from: req.context.userId, message: req.data, }); } res.success();
    
    

    I followed this git and doc to send and Listen messages with Azure Web PubSub.

    sending messages

      async send() {
        try {
          const chat = {
            from: this.user,
            message: this.message,
          };
    
          this.appendMessage(chat);
          await this.client.sendToGroup("chat", chat, "json", { noEcho: true });
          
          this.message = '';
    
    
    

    Listen to incoming messages

    
    appendMessage(data: any) {
        this.chats.push(data);
      }
    
    

    I have implemented the below angular code for sending and receiving messages to and from the Azure Web PubSub . If you are the user ,you have to use like i.e : http://localhost:8080/negotiate?id=${this.username}
    app.component.ts:

    
    import { Component } from '@angular/core';
    import { WebPubSubClient } from '@azure/web-pubsub-client';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      user: string = '';
      message: string = '';
      chats: any[] = [];
      connected: boolean = false;
      client: WebPubSubClient | null = null;
    
      async connect() {
        this.client = new WebPubSubClient({
          getClientAccessUrl: async () => (await fetch("http://localhost:8080/negotiate")).text(),
        });
    
        this.client.on("group-message", (e) => {
          const data = e.message.data;
          this.appendMessage(data);
        });
    
        await this.client.start();
        await this.client.joinGroup("chat");
        this.connected = true;
      }
    
      async send() {
        try {
          const chat = {
            from: this.user,
            message: this.message,
          };
    
          this.appendMessage(chat);
          await this.client.sendToGroup("chat", chat, "json", { noEcho: true });
          
          this.message = '';
        } catch (error) {
          console.error("Error sending message:", error);
          alert("Failed to send message. Please try again.");
        }
      }
      
    
    
    @Component({
      selector: 'user-chat',
      template: `
        <div class="align-self-start">
          <small class="text-muted font-weight-light">from {{ from }}</small>
          <p class="alert alert-primary text-break">{{ message }}</p>
        </div>
      `
    })
    export class UserChatComponent {
      @Input() from: string;
      @Input() message: string;
    }
    
    @Component({
      selector: 'self-chat',
      template: `<div class="align-self-end alert-success alert">{{ message }}</div>`
    })
    export class SelfChatComponent {
      @Input() message: string;
    }
    
    @Component({
      selector: 'app-login',
      template: `
        <div class="d-flex h-100 flex-column justify-content-center container">
          <div class="input-group m-3">
            <input
              autofocus
              type="text"
              class="form-control"
              placeholder="Username"
              [(ngModel)]="user"
            />
            <div class="input-group-append">
              <button
                class="btn btn-primary"
                type="button"
                [disabled]="!user"
                (click)="connect()"
              >
                Connect
              </button>
            </div>
          </div>
        </div>
      `
    })
    export class LoginComponent {
      @Input() user: string;
      @Output() connect = new EventEmitter<void>();
    }
    
    @Component({
      selector: 'app-messages',
      template: `
        <div class="h-100 container">
          <div class="chats d-flex flex-column m-2 p-2 bg-light h-100 overflow-auto">
            <ng-container *ngFor="let item of chats; let index = index">
              <ng-container *ngIf="item.from === user; else userChat">
                <self-chat [message]="item.message"></self-chat>
              </ng-container>
              <ng-template #userChat>
                <user-chat [from]="item.from" [message]="item.message"></user-chat>
              </ng-template>
            </ng-container>
          </div>
          <div class="input-group m-3">
            <input
              type="text"
              class="form-control"
              [placeholder]="'Hi ' + user + ', type a message'"
              [(ngModel)]="message"
            />
            <div class="input-group-append">
              <button class="btn btn-primary" type="button" (click)="send()">
                Send
              </button>
            </div>
          </div>
        </div>
      `
    })
    export class MessagesComponent {
      @Input() user: string;
      @Input() chats: any[];
      @Input() message: string;
      @Output() send = new EventEmitter<void>();
    }
    
    

    app.component.html :

    
    <app-login *ngIf="!connected" [(user)]="user" (connect)="connect()"></app-login>
    <app-messages *ngIf="connected" [user]="user" [chats]="chats" [(message)]="message" (send)="send()"></app-messages>
    
    
    

    Refer to this document for the server code to handle Azure Web PubSub connections.

    Output:
    enter image description here

    enter image description here

    enter image description here

    enter image description here