How to use shinymanager along with session$onSessionEnded() to close the app upon browser close

439 views Asked by At

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.

1

There are 1 answers

2
ismirsehregal On BEST ANSWER

{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)