* VRFS-2104 - client update dialog happens when it needs to; not just on startup

This commit is contained in:
Seth Call 2014-08-31 10:30:59 -05:00
parent 4dcbd34d9e
commit 5f85908c79
22 changed files with 306 additions and 110 deletions

View File

@ -75,9 +75,6 @@ group :libv8 do
gem 'libv8', "~> 3.11.8"
end
group :development do
gem 'thin' # bundle exec rails server thin
end
# To use Jbuilder templates for JSON
# gem 'jbuilder'

View File

@ -2,20 +2,34 @@ ActiveAdmin.register JamRuby::ArtifactUpdate, :as => 'Artifacts' do
menu :label => 'Artifacts'
config.sort_order = 'product,environment'
#config.batch_actions = false
#config.clear_action_items!
#config.filters = false
form :html => { :multipart => true } do |f|
f.inputs "Details" do
f.input :version, :hint => "Should match Jenkins build number of artifact"
f.input :environment, :hint => "Typically just 'public'"
f.input :product, :as => :select, :collection => JamRuby::ArtifactUpdate::PRODUCTS
end
f.inputs "Artifact Upload" do
f.input :uri, :as => :file, :hint => "Upload the artifact from Jenkins"
end
f.buttons
form :html => {:multipart => true} do |f|
f.inputs "Details" do
f.input :version, :hint => "Should match Jenkins build number of artifact"
f.input :environment, :hint => "Typically just 'public'"
f.input :product, :as => :select, :collection => JamRuby::ArtifactUpdate::PRODUCTS
end
f.inputs "Artifact Upload" do
f.input :uri, :as => :file, :hint => "Upload the artifact from Jenkins"
end
end
f.buttons
end
action_item :only => [:show] do
link_to('Send Client Update Notice', send_client_update_notice_admin_artifact_path(resource.id))
end
member_action :send_client_update_notice, :method => :get do
resource.send_notice
redirect_to :back
end
#collection_action :upload_artifact, :method => :post do
# # Do some CSV importing work here...

View File

@ -20,6 +20,10 @@ class ArtifactsController < ApplicationController
@artifact.uri = file
@artifact.save
if @artifact.save
@artifact.send_notice
end
end
unless @artifact.errors.any?

View File

@ -84,10 +84,13 @@ module JamAdmin
config.external_protocol = ENV['EXTERNAL_PROTOCOL'] || 'http://'
config.external_root_url = "#{config.external_protocol}#{config.external_hostname}#{(config.external_port == 80 || config.external_port == 443) ? '' : ':' + config.external_port.to_s}"
# where is rabbitmq?
config.rabbitmq_host = "localhost"
config.rabbitmq_port = 5672
# set to false to instead use amazon. You will also need to supply amazon secrets
config.store_artifacts_to_disk = false
#config.storage_type = :fog
config.storage_type = :fog
# these only need to be set if store_artifact_to_files = false
config.aws_access_key_id = ENV['AWS_KEY']
@ -96,6 +99,10 @@ module JamAdmin
config.aws_bucket_public = 'jamkazam-dev-public'
config.aws_bucket = 'jamkazam-dev'
config.aws_cache = '315576000'
config.aws_fullhost = "#{config.aws_bucket_public}.s3.amazonaws.com"
# cloudfront host
config.cloudfront_host = "d34f55ppvvtgi3.cloudfront.net"
# for carrierwave_direct
config.action_controller.allow_forgery_protection = false

View File

@ -0,0 +1,5 @@
unless $rails_rake_task
JamWebEventMachine.start
end

View File

@ -80,6 +80,10 @@ message ClientMessage {
PEER_MESSAGE = 310;
TEST_CLIENT_MESSAGE = 315;
// operational messages
CLIENT_UPDATE = 400;
GENERIC_MESSAGE = 401;
SERVER_BAD_STATE_RECOVERED = 900;
SERVER_GENERIC_ERROR = 1000;
@ -172,6 +176,10 @@ message ClientMessage {
optional PeerMessage peer_message = 310;
optional TestClientMessage test_client_message = 315;
// Server-to-All Client operational messages
optional ClientUpdate client_update = 400;
optional GenericMessage generic_message = 401;
// Server-to-Client special messages
optional ServerBadStateRecovered server_bad_state_recovered = 900;
@ -209,6 +217,7 @@ message LoginAck {
optional bool reconnected = 6; // if reconnect_music_session_id is specified, and the server could log the user into that session, then true is returned.
optional string user_id = 7; // the database user id
optional int32 connection_expire_time = 8; // this is how long the server gives you before killing your connection entirely after missing heartbeats
optional ClientUpdate client_update = 9;
}
// route_to: server
@ -600,7 +609,23 @@ message Heartbeat {
// target: client
// sent from server to client in response to a Heartbeat
message HeartbeatAck {
optional int32 track_changes_counter = 1;
optional int32 track_changes_counter = 1;
}
// target: client
// this needs to go to *every* client when it occurs
message ClientUpdate {
optional string product = 1;
optional string version = 2;
optional string uri = 3;
optional int32 size = 4;
}
// target: client
// this is meant to be a way to poke clients and do something meaningful that we didn't plan in advance
message GenericMessage {
optional string purpose = 1;
optional string message = 2;
}
// route_to: client

View File

@ -7,6 +7,7 @@ module JamRuby
SESSION_TARGET_PREFIX = "session:"
USER_TARGET_PREFIX = "user:"
CLIENT_TARGET_PREFIX = "client:"
ALL_NATIVE_CLIENTS = '__ALL_NATIVE_CLIENTS__' # special value used in place of a specific client ID
def initialize()
@type_values = {}
@ -67,7 +68,14 @@ module JamRuby
end
# create a login ack (login was successful)
def login_ack(public_ip, client_id, token, heartbeat_interval, music_session_id, reconnected, user_id, connection_expire_time)
def login_ack(public_ip, client_id, token, heartbeat_interval, music_session_id, reconnected, user_id, connection_expire_time, client_update_data = nil)
client_update = Jampb::ClientUpdate.new(
product: client_update_data[:product],
version: client_update_data[:version],
uri: client_update_data[:uri],
size: client_update_data[:size]
) if client_update_data
login_ack = Jampb::LoginAck.new(
:public_ip => public_ip,
:client_id => client_id,
@ -76,7 +84,8 @@ module JamRuby
:music_session_id => music_session_id,
:reconnected => reconnected,
:user_id => user_id,
:connection_expire_time => connection_expire_time
:connection_expire_time => connection_expire_time,
:client_update => client_update
)
Jampb::ClientMessage.new(
@ -719,6 +728,21 @@ module JamRuby
)
end
def client_update(product, version, uri, size)
client_update = Jampb::ClientUpdate.new(
product: product,
version: version,
uri: uri,
size: size
)
Jampb::ClientMessage.new(
:type => ClientMessage::Type::CLIENT_UPDATE,
:route_to => CLIENT_TARGET_PREFIX + ALL_NATIVE_CLIENTS,
:client_update => client_update
)
end
# create a band invitation message
def band_invitation(receiver_id, invitation_id, band_id, photo_url, msg, notification_id, created_at)
band_invitation = Jampb::BandInvitation.new(

View File

@ -2,9 +2,10 @@ module JamRuby
class ArtifactUpdate < ActiveRecord::Base
DEFAULT_ENVIRONMENT = 'public'
CLIENT_PREFIX = 'JamClient'
PRODUCTS = ["#{CLIENT_PREFIX}/Win32", "#{CLIENT_PREFIX}/MacOSX"]
PRODUCTS = ['JamClient/Win32', 'JamClient/MacOSX']
self.primary_key = 'id'
attr_accessible :version, :uri, :sha1, :environment, :product, as: :admin
@ -24,5 +25,28 @@ module JamRuby
end
end
def update_data
{product: product, version: version, uri: determine_url, size: size}
end
# called when the client is upgraded (sent to all native clients)
def send_notice
Notification.send_client_update(product, version, determine_url, size)
end
def self.find_client_by_os(os, environment=DEFAULT_ENVIRONMENT)
ArtifactUpdate.find_by_product_and_environment("#{CLIENT_PREFIX}/#{os}", environment)
end
def determine_url
if APP_CONFIG.storage_type == :file
# this is basically a dev-time only path of code; we store real artifacts in s3
url = APP_CONFIG.jam_admin_root_url + self.uri.url
else
url = self.uri.url.gsub(APP_CONFIG.aws_fullhost, APP_CONFIG.cloudfront_host)
end
url
end
end
end

View File

@ -1118,6 +1118,12 @@ module JamRuby
end
end
def send_client_update(product, version, uri, size)
msg = @@message_factory.client_update( product, version, uri, size)
@@mq_router.publish_to_all_clients(msg)
end
def send_text_message(message, sender, receiver)
notification = Notification.new

View File

@ -65,6 +65,10 @@ class MQRouter
end
end
# sends a message to all clients
def publish_to_all_clients(client_msg)
publish_to_client(MessageFactory::ALL_NATIVE_CLIENTS, client_msg)
end
# sends a message to a session with no checking of permissions (RAW USAGE)
# this method deliberately has no database interactivity/active_record objects

View File

@ -72,6 +72,7 @@
PING_REQUEST : "PING_REQUEST",
PING_ACK : "PING_ACK",
PEER_MESSAGE : "PEER_MESSAGE",
CLIENT_UPDATE : "CLIENT_UPDATE",
SERVER_BAD_STATE_RECOVERED: "SERVER_BAD_STATE_RECOVERED",
SERVER_GENERIC_ERROR : "SERVER_GENERIC_ERROR",
SERVER_REJECTION_ERROR : "SERVER_REJECTION_ERROR",

View File

@ -228,6 +228,10 @@
connectDeferred.resolve();
activeElementEvent('afterConnect', payload);
if(payload.client_update) {
context.JK.ClientUpdateInstance.runCheck(payload.client_update.product, payload.client_update.version, payload.client_update.uri, payload.client_update.size)
}
}
function heartbeatAck(header, payload) {
@ -527,7 +531,8 @@
channel_id: channelId,
token: $.cookie("remember_token"),
client_type: isClientMode() ? context.JK.clientType() : 'latency_tester',
client_id: isClientMode() ? (gon.global.env == "development" ? $.cookie('client_id') : null): context.jamClient.clientID
client_id: isClientMode() ? (gon.global.env == "development" ? $.cookie('client_id') : null): context.jamClient.clientID,
os: context.JK.GetOSAsString()
}
var uri = context.gon.websocket_gateway_uri + '?' + $.param(params); // Set in index.html.erb.

View File

@ -6,14 +6,13 @@
context.JK.ClientUpdate = function (app) {
var self = this;
var EVENTS = context.JK.EVENTS;
var logger = context.JK.logger;
var ellipsesJiggleTimer = null;
var forceShow = false; // manual test helper
var updateUri = null;
app.clientUpdating = false;
// updated once a download is started
var updateSize = 0;
@ -168,19 +167,50 @@
}
}
function runCheck(product, version, uri, updateSize, currentVersion) {
if(currentVersion === undefined) {
currentVersion = context.jamClient.ClientUpdateVersion();
if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) {
// this is a developer build; it doesn't make much sense to do an packaged update, so skip
logger.debug("skipping client update check because this is a development build ('" + currentVersion + "')")
return;
}
// # strange client oddity: remove quotes, if found, from start and finish of version.
if (currentVersion.indexOf('"') == 0 && currentVersion.lastIndexOf('"') == currentVersion.length - 1) {
currentVersion = currentVersion.substring(1, currentVersion.length - 1);
}
}
logger.debug("our client version: " + currentVersion + ", server client version: " + version);
// test url in lieu of having a configured server with a client-update available
if (shouldUpdate(currentVersion, version)) {
app.clientUpdating = true;
updateUri = uri;
if(context.JK.CurrentSessionModel && context.JK.CurrentSessionModel.inSession()) {
logger.debug("deferring client update because in session")
return;
}
// test metadata in lieu of having a configured server with a client-update available
//updateSize = 10000;
//version = "1.2.3"
// this will update the client dialog to how it should look when an update is just starting
// and show it front-and-center on the screen
updateClientUpdateDialog("update-start", { uri: updateUri })
}
}
// check if updated is needed
function check() {
var os = context.jamClient.GetOSAsString()
// check if method exists at all for migration purposes
if(context.jamClient.IsAppInWritableVolume && os == "MacOSX" && !context.jamClient.IsAppInWritableVolume()) {
context.JK.Banner.showAlert(
{ title: "JamKazam Needs Moving!",
buttons: [{name: 'SHUTDOWN APPLICATION', click: function() {context.jamClient.ShutdownApplication()}} ],
html: $('#template-app-in-read-only-volume').html()});
return;
}
var os = context.jamClient.GetOSAsString();
// check kill switch before all other logic
if (!gon.check_for_client_updates) {
@ -191,7 +221,6 @@
var product = "JamClient"
var currentVersion = context.jamClient.ClientUpdateVersion();
if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) {
// this is a developer build; it doesn't make much sense to do an packaged update, so skip
logger.debug("skipping client update check because this is a development build ('" + currentVersion + "')")
@ -207,23 +236,7 @@
type: "GET",
url: "/api/versioncheck?product=" + product + "&os=" + os,
success: function (response) {
var version = response.version;
logger.debug("our client version: " + currentVersion + ", server client version: " + version);
// test url in lieu of having a configured server with a client-update available
if (shouldUpdate(currentVersion, version)) {
updateSize = response.size;
app.clientUpdating = true;
// test metadata in lieu of having a configured server with a client-update available
//updateSize = 10000;
//version = "1.2.3"
// this will update the client dialog to how it should look when an update is just starting
// and show it front-and-center on the screen
updateClientUpdateDialog("update-start", { uri: response.uri })
}
runCheck(product, response.version, response.uri, response.size, currentVersion);
},
error: function (jqXHR, textStatus, errorThrown) {
logger.error("Unable to do a client update check against /api/versioncheck");
@ -263,12 +276,19 @@
app.bindDialog('client-update', {});
$(document).on(EVENTS.SESSION_ENDED, function(e, data){
if(app.clientUpdating) {
updateClientUpdateDialog("update-start", { uri: updateUri })
}
});
return self;
}
// Expose publics
this.initialize = initialize;
this.check = check;
this.runCheck = runCheck;
}
return this;

View File

@ -34,11 +34,25 @@
checkAudioStopped();
checkMacOSXInstalledCorrectly()
context.JK.onBackendEvent(ALERT_NAMES.SHOW_PREFERENCES, 'everywhere', function() {
app.layout.showDialog('client-preferences-dialog')
});
});
function checkMacOSXInstalledCorrectly() {
var os = context.jamClient.GetOSAsString();
// check if method exists at all for migration purposes
if(context.jamClient.IsAppInWritableVolume && os == "MacOSX" && !context.jamClient.IsAppInWritableVolume()) {
context.JK.Banner.showAlert(
{ title: "JamKazam Needs Moving!",
buttons: [{name: 'SHUTDOWN APPLICATION', click: function() {context.jamClient.ShutdownApplication()}} ],
html: $('#template-app-in-read-only-volume').html()});
return;
}
}
function initializeDialogs(app) {
var backendAlerts = new JK.BackendAlerts(app);

View File

@ -33,7 +33,9 @@
SHOW_SIGNIN : 'show_signin',
RSVP_SUBMITTED: 'rsvp_submitted',
RSVP_CANCELED : 'rsvp_canceled',
USER_UPDATED : 'user_updated'
USER_UPDATED : 'user_updated',
SESSION_STARTED : 'session_started',
SESSION_ENDED : 'session_stopped'
};
context.JK.ALERT_NAMES = {

View File

@ -131,8 +131,9 @@
// and other parts of the code want to know at any certain times
// about the current session, if any (for example, reconnect logic)
if(context.JK.CurrentSessionModel) {
context.JK.CurrentSessionModel.unsubscribe();
context.JK.CurrentSessionModel.ensureEnded();
}
context.JK.CurrentSessionModel = sessionModel = new context.JK.SessionModel(
context.JK.app,
context.JK.JamServer,
@ -140,7 +141,7 @@
self
);
sessionModel.setId(sessionId);
sessionModel.start(sessionId);
// indicate that the screen is active, so that
// body-scoped drag handlers can go active
screenActive = true;

View File

@ -10,6 +10,7 @@
// screen can be null
context.JK.SessionModel = function(app, server, client, sessionScreen) {
var ALERT_TYPES = context.JK.ALERT_TYPES;
var EVENTS = context.JK.EVENTS;
var userTracks = null; // comes from the backend
var clientId = client.clientID;
@ -29,6 +30,7 @@
var $self = $(this);
var sessionPageEnterDeferred = null;
var sessionPageEnterTimeout = null;
var startTime = null;
server.registerOnSocketClosed(onWebsocketDisconnected);
@ -36,8 +38,9 @@
return currentSession ? currentSession.id : null;
}
function setId(sessionId) {
function start(sessionId) {
currentSessionId = sessionId;
startTime = new Date().getTime();
}
function setUserTracks(_userTracks) {
@ -144,10 +147,10 @@
server.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
server.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
$(document).trigger('jamkazam.session_started', {session: {id: sessionId}});
$(document).trigger(EVENTS.SESSION_STARTED, {session: {id: sessionId}});
})
.fail(function() {
currentSessionId = null;
updateCurrentSession(null);
});
return deferred;
@ -183,8 +186,6 @@
//context.jamClient.SessionSetAlertCallback("");
context.jamClient.SessionSetConnectionStatusRefreshRate(0);
updateCurrentSession(null);
$(document).trigger('jamkazam.session_stopped', {session: {id: currentSessionId}});
currentSessionId = null;
}
/**
* Leave the current session, if there is one.
@ -249,21 +250,38 @@
}
}
// universal place to clean up, reset items
function sessionEnded() {
//cleanup
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
server.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
if(sessionPageEnterDeferred != null) {
sessionPageEnterDeferred.reject('session_over');
sessionPageEnterDeferred = null;
}
userTracks = null;
startTime = null;
$(document).trigger(EVENTS.SESSION_ENDED, {session: {id: currentSessionId}});
currentSessionId = null;
}
// you should only update currentSession with this function
function updateCurrentSession(sessionData) {
if(sessionData != null) {
currentOrLastSession = sessionData;
}
var beforeUpdate = currentSession;
currentSession = sessionData;
if(sessionData == null) {
//cleanup
if(sessionPageEnterDeferred != null) {
sessionPageEnterDeferred.reject('session_over');
sessionPageEnterDeferred = null;
}
userTracks = null;
// the 'beforeUpdate != null' makes sure we only do a clean up one time internally
if(sessionData == null && beforeUpdate != null) {
sessionEnded();
}
}
@ -564,7 +582,7 @@
// Public interface
this.id = id;
this.setId = setId;
this.start = start;
this.setUserTracks = setUserTracks;
this.recordedTracks = recordedTracks;
this.participants = participants;
@ -595,10 +613,8 @@
this.getParticipant = function(clientId) {
return participantsEverSeen[clientId]
};
this.unsubscribe = function() {
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
this.ensureEnded = function() {
updateCurrentSession(null);
}
};

View File

@ -4,6 +4,7 @@
context.JK = context.JK || {};
context.JK.Sidebar = function(app) {
var EVENTS = context.JK.EVENTS;
var logger = context.JK.logger;
var friends = [];
var rest = context.JK.Rest();
@ -97,12 +98,12 @@
// session events for chat
function registerSessionEvents() {
$(document).on('jamkazam.session_started', function(e, data){
$(document).on(EVENTS.SESSION_STARTED, function(e, data){
chatPanel.sessionStarted(e, data);
return false;
});
$(document).on('jamkazam.session_stopped', function(e, data) {
$(document).on(EVENTS.SESSION_ENDED, function(e, data) {
chatPanel.sessionStopped(e, data);
return false;
});

View File

@ -590,7 +590,12 @@
// * Unix
context.JK.GetOSAsString = function() {
if(!os) {
os = context.jamClient.GetOSAsString();
if(context.jamClient.IsNativeClient()) {
os = context.jamClient.GetOSAsString();
}
else {
os = context.JK.detectOS();
}
}
return os;
}

View File

@ -9,7 +9,7 @@ class ArtifactsController < ApiController
result = {}
clients.each do |client|
url = determine_url(client)
url = client.determine_url
result[client.product] = { :uri => url, :size => client.size }
end
render :json => result, :status => :ok
@ -47,23 +47,10 @@ class ArtifactsController < ApiController
if @artifact.nil?
render :json => {}, :status => :ok
else
url = determine_url(@artifact)
url = @artifact.determine_url
render :json => { "version" => @artifact.version, "uri" => url, "sha1" => @artifact.sha1, "size" => @artifact.size }, :status => :ok
end
end
def determine_url(artifact)
if SampleApp::Application.config.storage_type == :file
# this is basically a dev-time only path of code; we store real artifacts in s3
url = SampleApp::Application.config.jam_admin_root_url + artifact.uri.url
else
url = artifact.uri.url.gsub(SampleApp::Application.config.aws_fullhost,SampleApp::Application.config.cloudfront_host)
end
return url
end
end

View File

@ -154,6 +154,10 @@
var audioProfileInvalidDialog = new JK.AudioProfileInvalidDialog(JK.app);
audioProfileInvalidDialog.initialize();
var clientUpdate = new JK.ClientUpdate(JK.app);
JK.ClientUpdateInstance = clientUpdate;
clientUpdate.initialize();
var homeScreen = new JK.HomeScreen(JK.app);
homeScreen.initialize();
@ -243,6 +247,9 @@
var testBridgeScreen = new JK.TestBridgeScreen(JK.app);
testBridgeScreen.initialize();
// do a client update early check upon initialization
JK.ClientUpdateInstance.check()
JK.app.initialRouting();
JK.hideCurtain(300);
}
@ -262,11 +269,13 @@
JK.app.initialize();
// do a client update early check upon initialization
var clientUpdate = new JK.ClientUpdate(JK.app)
clientUpdate.initialize().check()
JK.JamServer.registerMessageCallback(JK.MessageType.CLIENT_UPDATE, function(header, payload) {
// do a client update early check upon initialization
JK.ClientUpdateInstance.runCheck(payload.product, payload.version, payload.uri, payload.size)
});
JK.TickDuration('.feed-entry.music-session-history-entry .inprogress .tick-duration');
JK.TickDuration('.feed-entry.music-session-history-entry .inprogress .tick-duration');
JK.JamServer.connect() // singleton here defined in JamServer.js
.done(function() {

View File

@ -180,28 +180,47 @@ module JamWebsockets
routing_key = headers.routing_key
client_id = routing_key["client.".length..-1]
@semaphore.synchronize do
client_context = @client_lookup[client_id]
if !client_context.nil?
client = client_context.client
if client_id == MessageFactory::ALL_NATIVE_CLIENTS
msg = Jampb::ClientMessage.parse(msg)
@log.debug "client-directed message received from #{msg.from} to all clients"
@client_lookup.each do |client_id, client_context|
if client_context.client_type == JamRuby::Connection::TYPE_CLIENT
client = client_context.client
@log.debug "client-directed message received from #{msg.from} to client #{client_id}"
unless client.nil?
EM.schedule do
@log.debug "sending client-directed down websocket to #{client_id}"
send_to_client(client, msg)
if client
EM.schedule do
@log.debug "sending client-directed down websocket to #{client_id}"
send_to_client(client, msg)
end
end
end
else
@log.debug "client-directed message unroutable to disconnected client #{client_id}"
end
else
@log.debug "Can't route message: no client connected with id #{client_id}"
client_context = @client_lookup[client_id]
if !client_context.nil?
client = client_context.client
msg = Jampb::ClientMessage.parse(msg)
@log.debug "client-directed message received from #{msg.from} to client #{client_id}"
unless client.nil?
EM.schedule do
@log.debug "sending client-directed down websocket to #{client_id}"
send_to_client(client, msg)
end
else
@log.debug "client-directed message unroutable to disconnected client #{client_id}"
end
else
@log.debug "Can't route message: no client connected with id #{client_id}"
end
end
end
rescue => e
@log.error "unhandled error in messaging to client"
@ -550,6 +569,7 @@ module JamWebsockets
client_id = options["client_id"]
reconnect_music_session_id = options["music_session_id"]
client_type = options["client_type"]
os = options["os"]
@log.info("handle_login: client_type=#{client_type} token=#{token} client_id=#{client_id} channel_id=#{client.channel_id}")
@ -663,6 +683,10 @@ module JamWebsockets
end
end
# if we have OS data, try to grab client update data and let the client have it
update = ArtifactUpdate.find_client_by_os(os) if os
client_update = update.update_data if update
login_ack = @message_factory.login_ack(remote_ip,
client_id,
user.remember_token,
@ -670,7 +694,8 @@ module JamWebsockets
connection.try(:music_session_id),
reconnected,
user.id,
connection_expire_time)
connection_expire_time,
client_update)
send_to_client(client, login_ack)
end
else