Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get connection id from composable #5

Open
rahmedd opened this issue Jan 7, 2025 · 3 comments
Open

Get connection id from composable #5

rahmedd opened this issue Jan 7, 2025 · 3 comments

Comments

@rahmedd
Copy link

rahmedd commented Jan 7, 2025

Hi, thank you for your work on this library!

I'm making a multiplayer game, with multiple game lobbies. I want to make an HTTP request to an ASP.NET API to ensure that the game lobby name requested is unique, and then use hubcontext within that same ASP.NET controller to add that player to the SignalR group. Because I'm using the SignalR hubcontext in an ASP.NET controller, it has no access to the SignalR event state/context and doesn't know what the connectionId is, so I need to pass the connectionId as part of my HTTP request.

I want to be able to send the SignalR connectionId from the Vue client to the ASP.NET endpoint.
How can I do that? Is there a way to access the connection instance after it's been connected? Somewhere after vue-signlar init() calls connection.start()?

Frontend (initialization) main.ts

...
const connection = new HubConnectionBuilder()
	.withUrl('/api/hub')
	.withAutomaticReconnect()
	.build()

const app = createApp(App)

app.use(VueSignalR, {
	connection,
	autoOffInsideComponentScope: true,
	failFn: () => {
		console.log('signalr conn failed.')
	},
})
...

Frontend usage store.ts

export const useRoom = defineStore('room', () => {
	const signalr = useSignalR()
	const roomState = ref<Room | null>(null)

	signalr.on('Send', message => {
		console.log(`Send: ${JSON.stringify(message)}`)
	})

	signalr.on('JSON-room', message => {
		const res = JSON.parse(message)
		console.log(res)
		roomState.value = res
	})

	async function createGame(roomCode: string, nickname: string) {
		try {
			const res = await axios.post(`${import.meta.env.VITE_API_URL}/Room/CreateGame`, {
				connectionId: 'NOT_IMPLEMENTED',
				groupName: roomCode,
				username: nickname,
			})

			if (!res.data.success) {
				// handle game already exists error
			}
		}
		catch (ex) {
			console.log(ex)
		}
	}
})

Backend:

...
[HttpPost("CreateGame")]
public async Task<Results<Ok<BaseResponseEmpty>, ValidationProblem>> CreateGame(
	string connectionId,
	string groupName,
	string username
)
{
	var room = await _roomService.GetRoom(groupName);
	if (room != null)
	{
		return TypedResults.Ok(new BaseResponseEmpty(false, "Room already exists"));
	}

	await _roomService.CreateRoom(connectionId, groupName, username);
	await _hubContext.Groups.AddToGroupAsync(connectionId, groupName);

	var gameStateJson = await _roomService.GetRoomAsJson(groupName);
	await _hubContext.Clients.Group(groupName).SendAsync("JSON-room", gameStateJson); // push updated game state to all players
	
	return TypedResults.Ok(new BaseResponseEmpty(true, "Game created"));
}
...
@IlCallo
Copy link
Member

IlCallo commented Jan 7, 2025

Hey there, I'm not sure how you could get that, but surely SignalR client, upon which we built this package, have some way of accessing that piece of information

It feels weird that you need to provide it from your client instead just inferring it server side, are you sure there isn't another way?

IIRC latest SignalR iterations started managing the connection id behind the curtains on purpose to avoid users the hassle to it themselves

@rahmedd
Copy link
Author

rahmedd commented Jan 19, 2025

There's no way to access the connectionId in the controller without mapping the signalR connectionId to the UserID in some way before making the HTTP request. This is an free/open game with no accounts so it's much harder to correlate, I wouldn't be able to use Identity framework and it's sessions since I don't think it will assign it a sessionId without logging in.

I was debugging main.ts, It looks like once the connection has been established I can get connection.connectionId, but there's no way for me to expose this or use it reactively in main.ts. Is there a way I can access the signalR instance through the composable?

@IlCallo
Copy link
Member

IlCallo commented Jan 20, 2025

I don't think it will assign it a sessionId without logging in

Have you actually tried it or are you guessing?

Is there a way I can access the signalR instance through the composable?

As explained in this package README, you're the one in charge of creating the connection in the first place, you should keep a reference to it

import { VueSignalR } from "@dreamonkey/vue-signalr";
import { HubConnectionBuilder } from "@microsoft/signalr";
import { createApp } from "vue";
import App from "./App.vue";

// Create your connection
// See https://docs.microsoft.com/en-us/javascript/api/@microsoft/signalr/hubconnectionbuilder
const connection = new HubConnectionBuilder() <====== Keep a reference of this  
  .withUrl("http://localhost:5000/signalr")
  .build();

createApp(App).use(VueSignalR, { connection }).mount("#app");

The composable returns a service which doesn't keep an internal reference to the connection other than the parameter you provide during initialization

We could easily return it from here:

vue-signalr/src/service.ts

Lines 124 to 131 in 6f9e461

return {
init,
connected,
invoke,
on,
off,
once,
};

But I'd keep the API lean and avoid that, since you already have a mean to get the connection reference yourself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants