SignalR restore connection - signalr

how do I restore connection without refreshing the client app browser if the backend server goes down, and comes back up in 5min or so...
const connection = new signalR.HubConnectionBuilder()
.withUrl(`/place/${props.match.params.id}`)
.withAutomaticReconnect()
.build();
connection.onreconnecting(function() {
setError('connection lost..');
var reconnectionInterval = setInterval(() => {
if (connection.state == signalR.HubConnectionState.Disconnected) {
connection.stop();
try {
console.log('try to reconnect');
connection.start();
} catch (e) {
//doesn't go here, how to handle if the server still down
console.log('failed to reconnect');
}
}
}, 5000);
});

This seems to work
if (connection.state == signalR.HubConnectionState.Disconnected) {
connection.start()
.then(x => {
clearInterval(reconnectionInterval);
setError(null);
})
.catch(ex => setError('still disconnected'));
}

Related

firebase auth with vue router

I have the authorization check code and it works. Now I need to implement path protection for an unauthorized user.
The problem is that the function in the storage does not have time to work out as it is already necessary to go along the path. AuthState and LoginStatus
try do it from getters, get actual state and try get data from state, but nothing happened
When I reload the page or clear the cache everything resets
//STORE
// call it first from app in created()
state: () => ({
isAuthReady: null,
}),
async AuthState({ dispatch }) {
await auth.onAuthStateChanged((userFirebase) => {
dispatch("LoginStatus", userFirebase);
});
},
LoginStatus({ commit, dispatch }, user) {
//console.log(user)
if (user) {
commit("setAuthReady", true);
commit("setUser", user);
dispatch("UserProfile", user);
dispatch("isAdmin");
} else {
// User is signed out
// ...
}
},
//ROUTER
{
path: "/admin",
component: () => import("#/pages/adminPage/admin"),
meta: { requiresAuth: true },
}
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresAuth) {
if (store.state.user.userInfo.length || store.state.user.userInfo.id) {
next();
} else {
await store.dispatch("auth/openLoginForm");
next("/");
}
} else next();
});
I don’t know if I did it right, but as recommended in this Answer, I think this is possible in firebase.
router.beforeEach((to, from, next) => {
auth.onAuthStateChanged(async (userFirebase) => {
if (to.meta.requiresAuth) {
if (userFirebase) {
next();
} else {
await store.dispatch("auth/openLoginForm");
next("/");
}
} else next();
});
});

MassTransit SignalR Bindings

I'm having some issues setting up my MassTransit SignalR solution. I have posted a question before regarding bindings which Chris answered and helped me out but after updating the packages (i was still using 6.x.x which had other issues like restarting RabbitMQ service would origin in an error when sending messages) my bindings don't seem to work properly anymore.
This was the first question i asked: Exchange binding not working in MassTransit with RabbitMQ and SignalR
Now i have updated to the 7.1.7 and also updated the methods that were deprecated. This is how my Startup looks like:
public void ConfigureServices(IServiceCollection services)
{
Utilities utilities = new Utilities(Configuration);
RabbitMQIdentity rabbitMQIdentity = utilities.GetRabbitMQIdentity();
var username = rabbitMQIdentity.UserName;
var password = rabbitMQIdentity.Password;
var hostName = rabbitMQIdentity.HostName;
var portNumber = rabbitMQIdentity.Port;
services.AddHttpClient();
services.AddControllers();
services.AddSignalR(e => {
e.EnableDetailedErrors = true;
e.MaximumReceiveMessageSize = 102400000;
});
services.AddMassTransit(x =>
{
x.AddSignalRHub<NotificationHub>();
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host($"amqp://{username}:{password}#{hostName}:{portNumber}");
cfg.AutoDelete = true;
cfg.Durable = false;
cfg.QueueExpiration = TimeSpan.FromMinutes(10);
cfg.ConfigureEndpoints(context);
});
});
services.AddMassTransitHostedService();
services.AddSingleton<IHostEnvironment>(hostEnvironment);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<LogConfigurationUtility, WebLogConfigurationUtility>();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.SetIsOriginAllowed((x) => Configuration["CorsWhiteList"].Split(';').Any(x.Contains))
.WithMethods("GET", "POST")
.AllowAnyHeader()
.AllowCredentials();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseMiddleware<RequestMiddleware>();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/notificationhub");
});
}
And here is my publish:
logger.LogInformation($"MassTransit publishing group message. GroupName:{paymentCallback.OrderId} ; Message:{paymentCallback.Event}");
IReadOnlyList <IHubProtocol> protocols = new IHubProtocol[] { new JsonHubProtocol() };
publishEndpoint.Publish<Group<NotificationHub>>(
new GroupHub<NotificationHub>()
{
GroupName = paymentCallback.OrderId,
Messages = protocols.ToProtocolDictionary("Notify", new object[] { paymentCallback.Event })
},
context => context.TimeToLive = TimeSpan.FromMinutes(10)
);
And the client:
useEffect(() => {
$(function() {
const connection = new HubConnectionBuilder()
.withUrl(hubUrl)
.configureLogging(LogLevel.Trace)
.build();
// Create a function that the hub can call to broadcast messages.
connection.on("Notify", (status) => {
console.log("entrouuuuuu");
setNotification(status);
});
// Start the connection.
async function start() {
try {
await connection.start();
connection.invoke("InitializeClient", orderId);
console.log("SignalR Connected.");
} catch (err) {
setTimeout(start, 5000);
}
}
start();
});
So now, in RabbitMQ management tools i can see the exchange being created but again it has no bindings and it has also no queues. Does the same issue still persist Chris? Or am i doing something wrong?
Thanks for the help!

SignalR Multiple Hub Connection .NET Core

I have 2 Hub classes,
SystemNotificationHub.cs
public class SystemNotificationHub : Hub { }
QuotationChatHub.cs
public class QuotationChatHub: Hub { }
SystemNotificationHub is defined in _Layout.cshtml so user is connected to hub continously,
and when user enters to QuotationChat.cshtml page, I want also same user to connect the QuotationChatHub, so in a simple manner I'd like the user to connect multiple hubs at the same time.
I cannot let user to connect more than 1 hub at the same time. How can I achive this?
StartUp endPoint Configurations
endpoints.MapHub<SystemNotificationHub>("/systemNotificationHub");
endpoints.MapHub<QuotationHub>("/quotationHub");
quotationChat.js
$(function () {
if (connection === null) {
connection = new signalR.HubConnectionBuilder()
.withUrl("/quotationHub")
.build();
connection.start().then(function () {
document.getElementById('sendButton').onclick = function () {
connection.invoke("BroadcastFromClient")
.catch(function (err) {
return console.error(err.toString());
});
};
});
}
});
notification.js
$(function () {
if (connection === null) {
connection = new signalR.HubConnectionBuilder()
.withUrl("/systemNotificationHub")
.build();
connection.on("Notify", function (response) {
});
connection.on("HubError", function (response) {
alert(response.error);
});
connection.start().then(function () {
connection.invoke("NotificationMethod")
.catch(function (err) {
return console.error(err.toString());
});
});
}
});
As far as I know, this issue is related with your if condition in your codes.
You have checked connection is null or not before creating the connection builder. But all two js use the same connection model.
To solve this issue, I suggest you could try to create a new connection for systemNotificationHub for example connection1 and then your code will work well.
More details, you could refer to below codes:
quotationChat.js not changed.
notification.js:
//Define a new connection1 as the new js object as connection
$(function () {
if (connection1 === null) {
connection1 = new signalR.HubConnectionBuilder()
.withUrl("/systemNotificationHub")
.build();
connection1.on("Notify", function (response) {
});
connection1.on("HubError", function (response) {
alert(response.error);
});
connection1.start().then(function () {
connection.invoke("NotificationMethod")
.catch(function (err) {
return console.error(err.toString());
});
});
}
});

push event not triggered in service worker

Following this tutorial until "Handle push event" section to setup a desktop notification system in my application, I face a problem:
When I click "push" to push a notification artificially with Chrome, no notification appear. No message in the console.
I allowed the notification from the website and the service-worker is well installed in my browser.
My service worker looks like this:
self.addEventListener('push', function (event) {
console.log('[Service Worker] Push Received.')
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`)
const title = 'My App Name'
const options = {
body: event.data.text(),
icon: 'pwa/icon.png',
badge: 'pwa/badge.png'
}
const notificationPromise = self.registration.showNotification(title, options)
event.waitUntil(notificationPromise)
})
and my service worker registration (using register-service-worker npm package) looks like this:
import { register } from 'register-service-worker'
const applicationServerPublicKey = 'BI5qCj0NdNvjDcBYTIXiNccdcP74Egtb3WxuaXrHIVCLdM-MwqPkLplHozlMsM3ioINQ6S_HAexCM0UqKMvaYmg'
function urlB64ToUint8Array (base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4)
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/')
const rawData = window.atob(base64)
const outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}
async function manageNotificationSubscription (registration) {
const subscription = await registration.pushManager.getSubscription()
let isSubscribed: boolean = !(subscription === null)
if (isSubscribed) {
console.log('User IS subscribed.')
} else {
console.log('User is NOT subscribed.')
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey)
try {
await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
console.log('User just subscribed.')
} catch (e) {
console.error('Failed to subscribe the user: ', e)
}
}
}
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.'
)
},
async registered (registration) {
console.log('Service worker has been registered.')
await manageNotificationSubscription(registration)
},
cached () {
console.log('Content has been cached for offline use.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
It looks like the push event in the service-worker is not even triggered...
Did I do something wrong?

Evothings and ddp

We are trying to connect our evothings app up to a meteor server.
To do this we are using a lib called asteroid. However we are unable to connect and run methods. We are absolutly sure this is not a server issue since we have some separate client code for testing that works flawlessly with it.
Evothings says it should work with websockets, and we aren't getting any error output, but all our method calls are returning nothing.
Here is the code:
var _asteroid = require('asteroid');
var Asteroid = (0, _asteroid.createClass)('password-login');
var asteroid = new Asteroid({ endpoint: 'wss://[url]/websocket' });
var currentLogin = null;
$('#login').submit(function(event) {
event.preventDefault();
login($('#login_username').val(), $('#login_password').val());
});
$('#create').submit(function(event) {
event.preventDefault();
newUser($('#create_username').val(), $('#create_password').val(), $('#create_id').val());
});
$('#occupy').click(function(event) {
setStatus(0);
});
$('#vacant').click(function(event) {
setStatus(1);
});
$('#refreash').click(function() {
getEmptyRooms();
});
window.newUser = function (username, password, roomId) {
$('#create_error').text('');
asteroid.call("accounts.newUser", username, password, roomId).then(function (result) {
console.log("Success");
login(username, password);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#create_error').text(error.message);
});
}
window.login = function (username, password) {
$('#login_error').text('');
asteroid.loginWithPassword({ username: username, password: password }).then(function (result) {
console.log(result);
currentLogin = result;
$('#current').html('Current User: ' + username);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#login_error').text(error.message);
});;
}
window.getEmptyRooms = function () {
asteroid.call("rooms.getAvailable").then(function (result) {
console.log(result);
$('#room_list').empty();
for(i = 0; i < result.length; i++) {
$('#room_list').append('<li>' + result[i] + '</li>');
}
}).catch(function (error) {
console.log("Error");
console.error(error);
});
}
window.setStatus = function (status) {
$('#status_error').text('');
if (currentLogin != null) {
asteroid.call("rooms.setStatus", status).then(function (result) {
console.log(result);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#status_error').text(error.message);
});
} else {
console.log('please login first');
$('#status_error').text('please login first');
}
}
As far as I know, the require() function works only in node.js, not in browser environment such as Evothings Viewer or Cordova, so you'll need some alternative means of loading the "asteroid" lib. Browserify?
How did you look for error output? The Evothings Tools window? If so, did you add this snippet to your index.html file?
<script>
// Redirect console.log to Evothings Workbench.
if (window.hyper && window.hyper.log) { console.log = hyper.log }
</script>
Perhaps this error isn't exclusive to the Evothings environment. Have you tested the app in a regular web browser?
Are you using proper certs?
Self signed will not work. The Evothings app is served via wss and since it runs "headless" so to speak (not a normal browser) it can't ask the user about allowing a self signed cert, so it will fail. Note that AFAIK ANY issue with the cert will make it fail.

Resources