2015-02-04 3 views
1

У меня есть node.js и socket.io, выполняющие обновления в реальном времени в таблице DataTables. Когда строка редактируется, другие клиенты видят обновления в строке без обновления.node.js/socket.io: Обновить таблицу при повторном подключении?

Это все работает хорошо, но я не понимаю, как автоматически обновляет таблицу, когда узел/сокет повторно подключается к серверу после отключения.

В настоящее время, это то, что происходит:

  1. Перейти на страницу, содержащую таблицу
  2. Пусть сон устройство/отключения от сервера
  3. Мощность на устройстве и увидеть страницу, содержащую таблицу
  4. гнездо. io повторно подключается к серверу, но таблица не обновляется, чтобы получить последние изменения.

Как я могу получить socket.io для обновления таблицы при повторном подключении к серверу? В идеале этот процесс будет выглядеть следующим образом:

  1. Мощность устройства
  2. socket.io подключится к серверу, триггеры CSS «Loading ...» оверлей для предотвращения пользователя от внесения изменений в таблицу
  3. гнездо .io обновляет таблицу, чтобы показать последние содержание
  4. CSS "Loading ..." оверлей закрывает

Серверный скрипт:

console.log('Starting the server'); 
var app = require('express')(); 
var express = require('express'); 
var fs = require("fs"); 

var server = require('https').createServer(SSL, app); 
var io = require('socket.io')(server); 
server.listen(100); 

io.on('connection', function (socket) { 
    /*socket.emit('news', { hello: 'world' }); 
    /socket.on('my other event', function (data) { 
    console.log(data); 
    });*/ 
}); 

io.set('authorization', function(handshakeData, accept) { 
    console.log('io.authorization called'); 
    accept(null, true); 
}); 

var lockedRowIDs = []; 

io.sockets.on('connection', function(socket) { 
    console.log('io.connection called'); 

    socket.on('lock', function(rowID) { 
     console.log('Lock event for rowID: '+rowID); 
     lock(socket, rowID); 
     lockedRowIDs.push(rowID); 
    }); 

    socket.on('clientJoin', function(username) { 
     console.log('clientJoin event received'); 
     socket.join('clients'); 
     if (typeof lockedRowIDs !== 'undefined' && lockedRowIDs.length > 0) { 
      socket.emit('lockedRows', lockedRowIDs); 
     } 
    }); 

    socket.on('unlock', function(rowID) { 
     console.log('Unlock event for rowID: '+rowID); 
     unlock(socket, rowID); 
     removeItemFromArray(lockedRowIDs, rowID); 
    }); 

    socket.on('updateData', function(json, action, id) { 
     if (action == "edit" || action == "create") { 
      console.log('updateData event for rowID: '+json.row['DT_RowId']); 
     } 
     updateData(socket, json, action, id); 
    }); 
}); 

function lock(socket, rowID) { 
    socket.broadcast.to('clients').emit('lock', rowID); 
    setTimeout(function() { 
     io.sockets.in('clients').emit('timeout', rowID); 
     removeItemFromArray(lockedRowIDs, rowID); 
    }, 
    180000); 
} 

function unlock(socket, rowID) { 
    socket.broadcast.to('clients').emit('unlock', rowID); 
} 

function removeItemFromArray(array, item) { 
    console.log('removeItemFromArray called with item: '+item); 
    for(var i = array.length - 1; i >= 0; i--) { 
     if(array[i] === item) { 
      array.splice(i, 1); 
     } 
    } 
} 

function updateData(socket, json, action, id) { 
    if (action == "edit" || action == "create") { 
     console.log('updateData called with rowID:'+json.row['DT_RowId']); 
    } 
    socket.broadcast.to('clients').emit('updateData', json, action, id); 
} 

сторона клиента сценарий:

var socket = io('https://www.***.com:100'); 
socket.on('connect', function() { 
    console.log('Connected'); 
    socket.emit('clientJoin'); 
}); 

socket.on('lock', function(rowID) { 
    console.log('Lock event received for rowID: '+rowID); 
    row = $("tr[id='"+rowID+"']"); 
    row.addClass('locked'); 
    /* Pagenation fix Start */ 
    var table = $('#example').DataTable(); 
    table.row('#'+rowID).nodes().to$().addClass('locked'); 
    /* Pagenation fix End */ 
}); 

socket.on('unlock', function(rowID) { 
    console.log('Unlock event received for rowID: '+rowID); 
    row = $("tr[id='"+rowID+"']"); 
    row.removeClass('locked'); 
    /* Pagenation fix Start */ 
    var table = $('#example').DataTable(); 
    table.row('#'+rowID).nodes().to$().removeClass('locked'); 
    /* Pagenation fix End */ 
}); 

socket.on('timeout', function(rowID) { 
    console.log('Time out event received for rowID: '+rowID); 
    row = $("tr[id='"+rowID+"']"); 
    row.removeClass('locked'); 
    /* Pagenation fix Start */ 
    var table = $('#example').DataTable(); 
    table.row('#'+rowID).nodes().to$().removeClass('locked'); 
    /* Pagenation fix End */ 
    /* Check if the editor corresponds to the timed out rowID - start */ 
    var modifier = editor.modifier(); 
    if (modifier) { 
     var data = table.row(modifier).data(); 
     console.log('rowID is '+data.DT_RowId); 
     if (data.DT_RowId == rowID) { 
      console.log('Timed out rowID: '+rowID+' matches Editor rowID: '+data.DT_RowId+'. Closing Editor now.'); 
      editor.close(); 
     } 
     else { 
      console.log('Timed out rowID: '+rowID+' does not match Editor rowID: '+data.DT_RowId+'. Keeping Editor open.'); 
     } 
    } 
    /* Check if the editor corresponds to the timed out rowID - end */ 
}); 

socket.on('lockedRows', function (rowIDs) { 
    console.log('Iterate through the list of rows and mark it as locked'); 
    table = $('#example').DataTable(); 
    rowCount = rowIDs.length; 
    console.log('Row count: '+rowCount); 
    for (var i=0; i<rowCount; i++) { 
     console.log(rowIDs[i]); 
     row = $("tr[id='"+rowIDs[i]+"']"); 
     row.addClass('locked'); 
     table.row('#'+rowIDs[i]).nodes().to$().addClass('locked'); 
    } 
}); 

socket.on('updateData', function(json, action, id) { 
    if (action == "create" || action == "edit") { 
     var DT_RowId = json.row['DT_RowId']; 
     console.log('updateData socket event for rowID: '+DT_RowId+' and action: '+action); 
    } 
    var table = $('table#example').DataTable(); 
    if (action == "edit") { 
     var editedRow = table.row('#'+DT_RowId).nodes().to$(); 
     table.row(editedRow).data(json.row).draw(); 
     console.log('Row updated'); 
    } 
    if (action == "create") { 
     console.log('Row created'); 
     table.row.add(json.row).draw(); 
    } 
    if (action == "remove") { 
     var removedRow = table.row('#'+id).nodes().to$(); 
     table.row(removedRow).remove().draw(); 
     console.log('Row removed with id '+id); 
    } 
}); 

/* Ajax request has been completed, data retrieved from the server */ 

editor.on('postSubmit', function(e,json, data, action) { 
    console.log('Post submit'); 
    console.log(data); 
    console.log('With JSON:'); 
    console.log(json); 
    console.log('With action:'); 
    console.log(action); 
    if (action == "create" || action== "edit") { 
     if (json.row){ 
      console.log('rowID from JSON: '+json.row['DT_RowId']); 
      socket.emit('updateData', json, action); 
     } 
    } 
    if (action == "remove") { 
     console.log('rowID from JSON: '+data.id[0]); 
     socket.emit('updateData', null, action, data.id[0]); 
    } 
}); 

editor.on('close', function(e) { 
    console.log('Close event'); 
    console.log(e); 
    var modifier = editor.modifier(); 
    console.log(modifier) 
    if (modifier !== null) { 
     console.log('Inside modifier') 
     table = $('#example').DataTable(); 
     if (table.row(modifier).node()) { 
      rowID = table.row(modifier).node().id; 
      console.log('rowID='+rowID); 
      row = $("tr[id='"+rowID+"']"); 
      row.removeClass('locked'); 
      table.row('#'+rowID).nodes().to$().removeClass('locked'); 
      socket.emit('unlock', rowID); 
     } 
    } 
}); 

ответ

3

Как я думаю, вы знаете, когда вы подключены, вы сохраняя данные уточненного, но если у вас есть мгновенное отключение, а затем повторное подключение, возможно, вы пропустили некоторые обновления данных.

Существует множество возможных стратегий для решения этой проблемы.

  1. Грубая сила. При повторном подключении получите свежую копию всех данных, как если бы устройство только что было включено. Менее эффективен, но прост в реализации.

  2. Идентификатор транзакции или время транзакции. Каждый раз, когда сервер отправляет обновление, он отправляет с этим обновлением либо идентификатор транзакции, либо время сервера транзакций. Затем клиент отслеживает последний идентификатор транзакции или время транзакции, которое он получил. Когда он повторно подключается, он отправляет начальное сообщение с последним идентификатором транзакции или временем транзакции с запросом любых обновлений, которые произошли после последней транзакции. Затем сервер может просмотреть свою базу данных, чтобы узнать, есть ли какие-либо новые транзакции, и если да, отправьте их этому клиенту. Это требует отслеживания транзакций в вашей базе данных. Обычно сервер может возвращать тип ответа «недействительный код транзакции», который затем заставляет клиента вернуться к грубому обновлению с нуля. Это означает, что восстановление базы данных или сбоя сервера приводит к потере старых значений транзакции.

  3. True Synchronization. Клиент повторно подключается, а затем выполняет настоящую синхронизацию с сервером, где клиент по существу говорит «это то, что у меня есть, у вас есть что-то новое». В интересах эффективности многие системы синхронизации решают эту проблему, реализуя идентификатор транзакции, описанный в варианте 2, но, безусловно, существует много других способов синхронизации. Истинная синхронизация более полезна, если клиент может также изменять данные во время их отсоединения.

Как упрощающий способ реализации варианты 2, если база данных уже не поддерживает идею журналируемых сделок, то некоторые сервера будут осуществлять журнал транзакций в памяти, где она отслеживает последние N часов сделок , Пока сервер остается в силе, а отключение длится не более N часов, запрос из новых данных может быть выполнен из журнала транзакций в памяти (что является эффективным). Если сервер перезагрузится или клиент ушел дольше, чем N часов, клиент просто вынужден выполнить грубое обновление, то же самое, что клиент сделал бы, если бы он был выключен, а затем снова включен (потерять все предварительное знание данных).

Конечно, если имеется несколько пользователей базы данных, журнал транзакций должен быть реализован самой базой данных, чтобы убедиться, что он включает в себя все возможные транзакции.

Смежные вопросы