是否有可能检测到当前正在交互一段html代码的用户数量?

时间:2016-08-12 10:48:36

标签: html google-apps-script concurrency google-sheets

这可能是一个天真的问题,对不起,但我正在尝试解决潜在的并发问题。我有一个注册程序,从用户从下拉菜单中选择他们的类别开始。这会触发对Google工作表中特定页面的查询,在该页面中,它会检索显示给用户的可用ID号。在按下最终提交按钮之前,需要几个步骤。这(我认为)为不止一个人创造了检索相同ID的机会。我确实使用google的lockservice,但使用了将表单信息写入我的电子表格的功能(基于Martin Hawksley的脚本)。如果可以确定当前正在查看注册页面的人数,我可以使用if语句在查询中使用该值,以便检索不同的行号。这样可以消除重复的可能性。

听起来合理吗?也许有更好的方法。

任何建议都会受到最高的赞赏。

1 个答案:

答案 0 :(得分:0)

  

如果可以确定当前正在查看的人数   注册页面

如果您不想使用Google Analytics。下面是一个简单示例,说明如何使用客户端轮询来维护会话,并计算有多少用户处于活动状态。

注意:我把它放在一起,它可能会被重构一点比较漂亮,但它应该得到它的要点

Working Example打开这几次,您会看到每个会话ID和一个计数。会话在没有活动60秒后过期,如果您关闭页面则会自动结束。

项目文件结构:

  • Code.gs
  • 的index.html
  • javascript.html

应用脚本

var sessionTimeout = 60; //60 seconds

//Triggered when the page is navigated to, serves up HTML
function doGet(){
  var template = HtmlService.createTemplateFromFile('index');
  template.userID = NewSession();
  return template.evaluate()
      .setTitle('Active Users')
      .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

/*================ Polling ================*/

//Client calls this function to poll, updates cache, returns active users
function ClientPoll(id){
  var scriptCache = CacheService.getScriptCache();
  UpdateScriptCache(id, 0, scriptCache, true);

  var activeIDs = GetActiveIDs(scriptCache);
  return activeIDs;
}

function EndSession(id){
  var scriptCache = CacheService.getScriptCache();
  scriptCache.remove(id);
  var activeIDs = GetActiveIDs(scriptCache);
  activeIDs.splice(activeIDs.indexOf(id), 1);
  UpdateScriptCache('ActiveIDs', activeIDs, scriptCache, false);
}

//Server calls every minute to check for inactive sessions
function CheckForInactiveSessions(){
  var scriptCache = CacheService.getScriptCache();
  var activeIDs = GetActiveIDs(scriptCache);
  var allSessions = scriptCache.getAll(activeIDs);

  if(Object.keys(allSessions).length > 0){
    var keys = Object.keys(allSessions);
    var newActiveIDs = [];

    for(var i = 0; i < keys.length; i++){
      newActiveIDs.push(keys[i]);

    }
    Logger.log(keys.length);
    UpdateScriptCache('ActiveIDs', newActiveIDs, scriptCache, false);
  }  
}

/*================ Session Creation & Cache ================*/

//Handles setting up a new session, called when page is opened
function NewSession(){
  var id = GenerateUID();
  AddNewActiveID(id);
  return id;
}

//Gets a list of all active IDs
function GetActiveIDs(scriptCache){

  if(!scriptCache){
    scriptCache = CacheService.getScriptCache();
  }

  var active = scriptCache.get('ActiveIDs');

  if(active !== null){
    return JSON.parse(active);
  }
  return [];
}

//Adds a new ID to the cache
function AddNewActiveID(id){
  var scriptCache = CacheService.getScriptCache();
  var activeIDs = JSON.parse(scriptCache.get('ActiveIDs'));
  if(activeIDs == null){
    activeIDs = [];
  }
  activeIDs.push(id);

  //Update the Active ID List
  UpdateScriptCache('ActiveIDs', activeIDs, scriptCache, false);

  //Add new ID to cache
  UpdateScriptCache(id, 0, scriptCache, true);
}

//Handles updating the Active IDs cache and prevents race conditions or collisions
function UpdateScriptCache(key, data, cache, timeout){
  var lock = LockService.getScriptLock();
  lock.waitLock(15000);
  if(timeout){
    cache.put(key, JSON.stringify(data), sessionTimeout);
  } else {
    cache.put(key, JSON.stringify(data), 21600)
  }


  lock.releaseLock();
}

/*================ ID Generation ================*/

//Handles generating and returning a new ID
function GenerateUID(){
  var generator = new IDGenerator();
  var id = generator.generate();
  return id;  
}

//Generates a random(ish) ID;
function IDGenerator() {

  this.length = 10;
  this.timestamp = new Date().getTime();

  var getRandomInt = function( min, max ) {
    return Math.floor( Math.random() * ( max - min + 1 ) ) + min;
  }

  this.generate = function(){
    var timestamp = this.timestamp.toString();
    var parts = timestamp.split('').reverse();
    var id = '';

    for(var i = 0; i < this.length; i++){
      var index = getRandomInt(0, parts.length - 1);
      id += parts[index];
    }

    return id;
  }

}

<强> JavaScript的:

<script>

//Initilization
$(function(){

  //Set the users ID in HTML
  $('#userID').text(userID);

  //Setup handler to end the session before the page closes
  $(window).bind('beforeunload', function(){
     EndSession();
  });  

  //Start the timer
  var deadline = new Date(Date.parse(new Date()) + 5000);
  initializeTimer('pollingIn', deadline);  
});



//Polls the server to update session and get active users
function PollServer(){
  console.log('Polling server');
  google.script.run.withSuccessHandler(UpdateActiveUsers).ClientPoll(userID);
  var deadline = new Date(Date.parse(new Date()) + 5000);
  initializeTimer('pollingIn', deadline);  
}

//Ends the session right before the page closes
function EndSession(){
  google.script.run.withSuccessHandler().EndSession(userID);
}

//Updates the active users div
function UpdateActiveUsers(users){
  console.log(users)

  var userText = '';
  for(var i = 0; i < users.length; i++){
    if(i == 0){
      userText += users[i];
      continue;
    }  
    userText += ', ' + users[i];
  }

  $('#activeUsersCount').text(users.length);
  $('#activeUsers').text(userText);
}

//Initilizes the timer
function initializeTimer(id, endtime) {
  var timer = $('#'+id);

  function updateTimer() {
    var time = Date.parse(endtime) - Date.parse(new Date());
    var seconds = Math.floor((time / 1000) % 60);
    timer.text(seconds);

    if (time <= 0) {
      clearInterval(timeInterval);
      PollServer();
    }
  }

  updateTimer();
  var timeInterval = setInterval(updateTimer, 1000);
}
</script>

<强> HTML:

<!DOCTYPE html>
<html>

    <head>
        <base target="_top">
        <link href="https://ssl.gstatic.com/docs/script/css/add-ons1.css" rel="stylesheet">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
    </head>

    <body>
        <div id="mainForm">
            <h1>Active Users</h1>
            <div class="box">
                Active Users Count:
                <span id="activeUsersCount">0</span>
            </div>            
            <div class="box">
                Active Users:
                <span id="activeUsers"></span>
            </div>
            <div class="box">
                Polling in:
                <span id="pollingIn"></span>
            </div>
            <div class="box">
                You Are:
                <span id="userID"></span>
            </div>            
        </div>
        <?!= HtmlService.createHtmlOutputFromFile('javascript').getContent(); ?>
        <script>
          var userID = <?= userID ?>;
        </script>
    </body>

</html>

<style>
    .box {
        display: block;
        padding: 0.5em;
    }

    body {
        padding: 1em;
    }
</style>