# 3. The other must be stopped, and must not have the domain names mapped to
# it. (just it's *.af.com address.)
#
-# For now, pass only the name of the app which is currently stopped.
+# Pass the app name without the underscore at the end, and app_publish_seamless
+# will figure out which is which
commands.app_publish_seamless = (token, app_name, zip_file, callback) ->
- # FIXME auto-detect which one is new by checking app_info.urls.length
- # (should happen for all api calls?)
- #
- # for now, we assume that the passed app_name is the currently dormant one
- if app_name.substr(-1) is '_'
- old_app = app_name.substr 0, app_name.length - 1
- new_app = app_name
- else
- old_app = app_name + '_'
- new_app = app_name
-
async.auto {
- push: (cb) => @api 'app_update_files', new_app, zip_file, cb
- # TODO find out if app_update_files increments app_info.version
- # if not, drop new_info's dependency on push
- old_info: (cb) => @api 'app_info', old_app, cb
- new_info: ['push', (cb) => @api 'app_info', new_app, cb ]
- start_new: ['push', 'old_info', 'new_info', (cb, args) =>
- args.new_info.state = 'STARTED'
- for u in args.old_info.uris
- args.new_info.uris.push u unless u.substr(-6) is '.af.cm'
- @api 'app_set_info', new_app, args.new_info, cb
+ info1: (cb) => @api 'app_info', app_name, cb
+ info2: (cb) => @api 'app_info', app_name + '_', cb
+ infos: ['info1', 'info2', (cb, args) ->
+ # FIXME check for other requirements and bail if not met
+ if args.info1.state is 'STOPPED'
+ cb null, new: args.info1, old: args.info2
+ else
+ cb null, new: args.info2, old: args.info1
+ ]
+ push: ['infos', (cb, args) =>
+ @api 'app_update_files', args.infos.new.name, zip_file, cb
+ ]
+ copy_uris: ['push', 'infos', (cb, args) =>
+ # There's a bug in the server where you can't set new uris and
+ # start the app in the same app_set_info call
+ for u in args.infos.old.uris
+ args.infos.new.uris.push u unless u.substr(-6) is '.af.cm'
+ @api 'app_set_info', args.infos.new.name, args.infos.new, cb
]
- hide_old: ['start_new', 'old_info', (cb, args) =>
+ new_info_again: ['copy_uris', 'infos', (cb, args) =>
+ @api 'app_info', args.infos.new.name, cb
+ ]
+ start_new: ['new_info_again', (cb, args) =>
+ args.new_info_again.state = 'STARTED'
+ @api 'app_set_info', args.new_info_again.name, args.new_info_again, cb
+ ]
+ hide_old: ['start_new', 'infos', (cb, args) =>
just_af = []
- for u in args.old_info.uris
+ for u in args.infos.old.uris
just_af.push u if u.substr(-6) is '.af.cm'
- args.old_info.uris = just_af
- @api 'app_set_info', old_app, args.old_info, cb
+ args.infos.old.uris = just_af
+ @api 'app_set_info', args.infos.old.name, args.infos.old, cb
]
wait_for_old_connections: ['hide_old', (cb) =>
seconds = 10
@log_end(log_id)
cb()
]
- old_info_again: ['hide_old', (cb) =>
- @api 'app_info', old_app, cb
+ old_info_again: ['hide_old', 'infos', (cb, args) =>
+ @api 'app_info', args.infos.old.name, cb
]
stop_old: ['wait_for_old_connections', 'old_info_again', (cb, args) =>
args.old_info_again.state = 'STOPPED'
- @api 'app_set_info', old_app, args.old_info_again, cb
+ @api 'app_set_info', args.old_info_again.name, args.old_info_again, cb
]
- # TODO when we get into sending manifests, we may need to update_files to old_app too
+ # TODO when we get into sending manifests, we may need to update_files to infos.old.name too
}, callback
app_set_state = (token, app_name, state, callback) ->
else
callback null, token
-login = (callback) ->
+login_callbacks = []
+login = (real_callback) ->
+ login_callbacks.push real_callback
+ return if login_callbacks.length > 1
+
+ callback = (err, token) ->
+ while login_callbacks.length > 0
+ login_callbacks.shift()(err, token)
+
async.waterfall [
(callback) => async.series [
(callback) => @ask prompt: 'username: ', callback