2

I have an application which uses the shinymanager library for user login. I want to use the session$onSessionEnded() to close my app once the browser is closed as suggested in the link Close Shiny App upon Browser close by Joe Chang

App is working fine without using the shinymanager. Any idea why this is happening ?

sample code:

library(shiny)
library(shinyWidgets)
library(shinythemes)
library(shinymanager)

credentials <- data.frame(
  user = c("admin", "shinymanager"), # mandatory
  password = c("admin", "12345"), # mandatory
  start = c("2022-04-15"), # optinal (all others)
  expire = c(NA, "2026-12-31"),
  admin = c(TRUE, TRUE),
  comment = "Simple and secure authentification mechanism 
  for single ‘Shiny’ applications.",
  stringsAsFactors = FALSE
)


ui <- fluidPage(
  sliderInput("n", "Number of observations", 2, 1000, 500),
  plotOutput("plot")
)

ui <- secure_app(ui)

server <- function(input, output, session) {

  res_auth <- secure_server(
    check_credentials = check_credentials(credentials)
  )
  
  session$onSessionEnded(function() {
    stopApp()
  })

  observe({
    # Re-execute this reactive expression after 1000 milliseconds
    invalidateLater(1000, session)
    print(paste("The value of input$n is", isolate(input$n)))
  })
  output$plot <- renderPlot({
    # Re-execute this reactive expression after 2000 milliseconds
    invalidateLater(2000)
    hist(rnorm(isolate(input$n)))
  })
}

shinyApp(ui, server)

Can someone suggest me workaround for this.

Phil
  • 7,287
  • 3
  • 36
  • 66
  • Related Github [issue](https://github.com/datastorm-open/shinymanager/issues/159). – ismirsehregal Jan 10 '23 at 08:41
  • Did you check my below answer by now? – ismirsehregal Feb 01 '23 at 13:02
  • Hi @ismirsehregal, Thanks for the new code. Its working fine with the shiny manager. I faced one more issue while testing. when i am sharing the app with other users. Lets say my app is running on a server with a dedicated ip. In parallel other users also accessing my app through my ip link in the web browser. In that case if any one of the user close the browser also the app is getting closed in the server. I am expecting the app should run in the server and it should close only if we close the app/browser in the server machine not in the client/other user stations. – Santhosh Manikandan May 27 '23 at 13:08

1 Answers1

1

{shinymanager}'s log-in screen runs in a separate shiny session, which is ended after a user logs in. Therefore your above app stops after log in.

Edit:

As an alternative to session$onSessionEnded() we can listen on the JS unload event:

library(shiny)
library(shinyWidgets)
library(shinythemes)
library(shinymanager)

credentials <- data.frame(
  user = c("admin", "shinymanager"), # mandatory
  password = c("admin", "12345"), # mandatory
  start = c("2022-04-15"), # optinal (all others)
  expire = c(NA, "2026-12-31"),
  admin = c(TRUE, TRUE),
  comment = "Simple and secure authentification mechanism 
  for single ‘Shiny’ applications.",
  stringsAsFactors = FALSE
)


ui <- fluidPage(
  tags$script(HTML("$(window).on('unload', function(event) {
                      Shiny.setInputValue(id = 'window_unload', value = true);
                    });")),
  sliderInput("n", "Number of observations", 2, 1000, 500),
  plotOutput("plot")
)

ui <- secure_app(ui)

server <- function(input, output, session) {
  res_auth <- secure_server(
    check_credentials = check_credentials(credentials)
  )
  
  observeEvent(input$window_unload, {
    print("stopApp()")
    stopApp()
  })
  
  observe({
    # Re-execute this reactive expression after 1000 milliseconds
    invalidateLater(1000, session)
    print(paste("The value of input$n is", isolate(input$n)))
  })
  output$plot <- renderPlot({
    # Re-execute this reactive expression after 2000 milliseconds
    invalidateLater(2000)
    hist(rnorm(isolate(input$n)))
  })
}

shinyApp(ui, server)

PS: you might want to check if the visibilitychange event works in your scenario.


Initial answer:

Accordingly we need to check if a user is logged in before running stopApp:

library(shiny)
library(shinyWidgets)
library(shinythemes)
library(shinymanager)

credentials <- data.frame(
  user = c("admin", "shinymanager"), # mandatory
  password = c("admin", "12345"), # mandatory
  start = c("2022-04-15"), # optinal (all others)
  expire = c(NA, "2026-12-31"),
  admin = c(TRUE, TRUE),
  comment = "Simple and secure authentification mechanism 
  for single ‘Shiny’ applications.",
  stringsAsFactors = FALSE
)


ui <- fluidPage(
  sliderInput("n", "Number of observations", 2, 1000, 500),
  plotOutput("plot")
)

ui <- secure_app(ui)

server <- function(input, output, session) {
  res_auth <- secure_server(
    check_credentials = check_credentials(credentials)
  )
  
  session$onSessionEnded(function() {
    print(paste("Session", session$token, "ended"))
    if(!is.null(isolate({res_auth$user}))){
      stopApp() 
    }
  })
  
  observe({
    # Re-execute this reactive expression after 1000 milliseconds
    invalidateLater(1000, session)
    print(paste("The value of input$n is", isolate(input$n)))
  })
  output$plot <- renderPlot({
    # Re-execute this reactive expression after 2000 milliseconds
    invalidateLater(2000)
    hist(rnorm(isolate(input$n)))
  })
}

shinyApp(ui, server)
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
  • Thanks for your answer ! for the sake of completeness, I have one more doubt/issue with the code. I tried the above code its working fine for the login but if I make a logout or going to administrator mode of shinymanager the app stops. I understand that the login/logout/administrator modes are running in a separate shiny session. could you please help me sort out this issue – Santhosh Manikandan Jan 09 '23 at 11:33
  • @SanthoshManikandan please see my alternative approach. – ismirsehregal Jan 10 '23 at 08:10