diff --git a/config/locales/en.yml b/config/locales/en.yml index 1389336..fac8fdb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -20,7 +20,14 @@ en: user: 'Owner user or organization name' udid: 'UDID to be registered' device_name: 'Device name to be registered' + distribution_key: 'If you also want to update distribution page, set the last part of the URL of the page' error: 'Commands::AddDevices Error: %{e}' + server: + description: 'Start the add-devices server. When added new device automatically run add-devices command.' + connecting: 'Connecting...' + start: 'Start add-devices server. Use Ctrl-C to stop.' + start_build: 'New device has been added. Start add-devices command.' + finish_build: 'add-devices completed successfully.' logout: description: 'Log out current session' error: 'Commands::Logout Error: %{e}' diff --git a/deploygate.gemspec b/deploygate.gemspec index 455c89c..9fb907f 100644 --- a/deploygate.gemspec +++ b/deploygate.gemspec @@ -34,6 +34,8 @@ POST_INSTALL_MESSAGE spec.add_dependency 'launchy' spec.add_dependency 'locale' spec.add_dependency 'net-ping' + spec.add_dependency 'socket.io-client-simple' + spec.add_dependency 'workers' # ios build spec.add_dependency 'gym', '~> 1.7.0' diff --git a/lib/deploygate.rb b/lib/deploygate.rb index 958c136..4c0ec16 100644 --- a/lib/deploygate.rb +++ b/lib/deploygate.rb @@ -19,6 +19,8 @@ require "launchy" require "webrick" require "net/ping" +require "socket.io-client-simple" +require "workers" require "i18n" I18n.load_path = Dir[File.join(File.dirname(__FILE__), '../config/locales/*.yml')] @@ -38,6 +40,7 @@ module DeployGate require "deploygate/api/v1/push" require "deploygate/api/v1/user" require "deploygate/api/v1/users/app" +require "deploygate/api/v1/users/apps/cli_websockets" require "deploygate/command_builder" require "deploygate/commands/login" require "deploygate/commands/logout" @@ -54,6 +57,7 @@ module DeployGate require "deploygate/project" require "deploygate/user" require "deploygate/browser_login" +require "deploygate/add_devices_server" require "deploygate/xcode/member_center" require "deploygate/xcode/member_centers/app" require "deploygate/xcode/member_centers/provisioning_profile" diff --git a/lib/deploygate/add_devices_server.rb b/lib/deploygate/add_devices_server.rb new file mode 100644 index 0000000..f61eaa4 --- /dev/null +++ b/lib/deploygate/add_devices_server.rb @@ -0,0 +1,79 @@ +module DeployGate + class AddDevicesServer + + def start(token, owner_name, bundle_id, distribution_key, args, options) + DeployGate::Xcode::MemberCenter.instance + options.server = false + + puts I18n.t('command_builder.add_devices.server.connecting') + res = DeployGate::API::V1::Users::Apps::CliWebsockets.create(token, owner_name, bundle_id, distribution_key) + + server = res[:webpush_server] + push_token = res[:push_token] + action = res[:action] + if res[:error] || server.blank? || push_token.blank? || action.blank? + raise res[:message] + end + + websocket_setup(server, bundle_id, push_token, action, args, options) do |socket| + puts HighLine.color(I18n.t('command_builder.add_devices.server.start'), HighLine::GREEN) + + Workers::PeriodicTimer.new(60) do + DeployGate::API::V1::Users::Apps::CliWebsockets.heartbeat(token, owner_name, bundle_id, distribution_key, push_token) + end + + Signal.trap(:INT){ + socket.disconnect + exit 0 + } + end + + loop do + sleep 60 + end + end + + def self.build(pool, bunlde_id, iphones, args, options) + iphones.reject! { |iphone| iphone['is_registered'] } # remove udids if already registered + devices = iphones.map do |iphone| + udid = iphone['udid'] + device_name= iphone['device_name'] + DeployGate::Xcode::MemberCenters::Device.new(udid, '', device_name) + end + return if devices.empty? + + puts HighLine.color(I18n.t('command_builder.add_devices.server.start_build'), HighLine::GREEN) + pool.perform do + DeployGate::Commands::AddDevices.register!(devices) + DeployGate::Commands::AddDevices.build!(bunlde_id, args, options) + puts HighLine.color(I18n.t('command_builder.add_devices.server.finish_build'), HighLine::GREEN) + puts '' + end + end + + private + + def websocket_setup(server, bundle_id, push_token, target_action, args, options, &block) + socket = SocketIO::Client::Simple.connect server + socket.on :connect do + socket.emit :subscribe, push_token + block.call(socket) + end + + socket.on :error do + raise 'Socket Error' + end + + pool = Workers::Pool.new(size: 1, on_exception: proc { |e| + raise e + }) + socket.on push_token do |push_data| + return if push_data['action'] != target_action + data = JSON.parse(push_data['data']) + + iphones = data['iphones'] + DeployGate::AddDevicesServer.build(pool, bundle_id, iphones, args, options) + end + end + end +end diff --git a/lib/deploygate/api/v1/base.rb b/lib/deploygate/api/v1/base.rb index 39c5b27..8109a7e 100644 --- a/lib/deploygate/api/v1/base.rb +++ b/lib/deploygate/api/v1/base.rb @@ -2,7 +2,7 @@ module DeployGate module API module V1 class Base - BASE_URL = 'https://deploygate.com' + BASE_URL = ENV['DG_DEVELOP_URL'] || 'https://deploygate.com' API_BASE_URL = "#{BASE_URL}/api" # @param [String] token diff --git a/lib/deploygate/api/v1/users/apps/cli_websockets.rb b/lib/deploygate/api/v1/users/apps/cli_websockets.rb new file mode 100644 index 0000000..0caa802 --- /dev/null +++ b/lib/deploygate/api/v1/users/apps/cli_websockets.rb @@ -0,0 +1,42 @@ +module DeployGate::API::V1::Users::Apps + class CliWebsockets + ENDPOINT = "/users/%s/platforms/%s/apps/%s/cli_websockets" + + class << self + def create(token, name, package_name, distribution_key, platform = 'ios') + params = {distribution_access_key: distribution_key} unless distribution_key.nil? + res = DeployGate::API::V1::Base.new(token).post(sprintf(ENDPOINT, name, platform, package_name), params || {}) + + results = { + error: res['error'] + } + if results[:error] + results.merge!( + { + message: res['message'] + } + ) + else + results.merge!( + { + push_token: res['results']['push_token'], + webpush_server: res['results']['webpush_server'], + action: res['results']['action'] + } + ) + end + + results + end + + def heartbeat(token, name, package_name, distribution_key, push_token, platform = 'ios') + params = {distribution_access_key: distribution_key} unless distribution_key.nil? + res = DeployGate::API::V1::Base.new(token).get("#{sprintf(ENDPOINT, name, platform, package_name)}/#{push_token}/heartbeat", params || {}) + + { + error: res['error'] + } + end + end + end +end diff --git a/lib/deploygate/command_builder.rb b/lib/deploygate/command_builder.rb index e2292da..a523bd2 100644 --- a/lib/deploygate/command_builder.rb +++ b/lib/deploygate/command_builder.rb @@ -80,8 +80,10 @@ def run c.option '--user STRING', String, I18n.t('command_builder.add_devices.user') c.option '--udid STRING', String, I18n.t('command_builder.add_devices.udid') c.option '--device-name STRING', String, I18n.t('command_builder.add_devices.device_name') + c.option '--distribution-key STRING', String, I18n.t('command_builder.add_devices.distribution_key') + c.option '--server', I18n.t('command_builder.add_devices.server.description') c.action do |args, options| - options.default :user => nil + options.default :user => nil, :server => false begin Commands::AddDevices.run(args, options) rescue => e diff --git a/lib/deploygate/commands/add_devices.rb b/lib/deploygate/commands/add_devices.rb index c27d3ca..fda39a6 100644 --- a/lib/deploygate/commands/add_devices.rb +++ b/lib/deploygate/commands/add_devices.rb @@ -15,21 +15,32 @@ def run(args, options) session = DeployGate::Session.new() end - owner = options.user || session.name - udid = options.udid - device_name = options.device_name + owner = options.user || session.name + udid = options.udid + device_name = options.device_name + distribution_key = options.distribution_key + server = options.server bundle_id = bundle_id(work_dir) + if server + run_server(session, owner, bundle_id, distribution_key, args, options) + else + device_register(session, owner, udid, device_name, bundle_id, args, options) + end + end + + def run_server(session, owner, bundle_id, distribution_key, args, options) + DeployGate::AddDevicesServer.new().start(session.token, owner, bundle_id, distribution_key, args, options) + end + + def device_register(session, owner, udid, device_name, bundle_id, args, options) if udid.nil? && device_name.nil? devices = fetch_devices(session.token, owner, bundle_id) select_devices = select_devices(devices) not_device if select_devices.empty? - select_devices.each do |device| - device.register! - success_registered_device(device) - end + register!(devices) else register_udid = udid || HighLine.ask(I18n.t('commands.add_devices.input_udid')) register_device_name = device_name || HighLine.ask(I18n.t('commands.add_devices.input_device_name')) @@ -37,13 +48,23 @@ def run(args, options) puts device.to_s if HighLine.agree(I18n.t('commands.add_devices.device_register_confirm')) {|q| q.default = "y"} - device.register! - success_registered_device(device) + register!([device]) else not_device end end + build!(bundle_id, args, options) + end + + def register!(devices) + devices.each do |device| + device.register! + success_registered_device(device) + end + end + + def build!(bundle_id, args, options) DeployGate::Xcode::MemberCenters::ProvisioningProfile.new(bundle_id).create! team = DeployGate::Xcode::MemberCenter.instance.team DeployGate::Xcode::Export.clean_provisioning_profiles(bundle_id, team) diff --git a/lib/deploygate/version.rb b/lib/deploygate/version.rb index fea10b0..f22c7b7 100644 --- a/lib/deploygate/version.rb +++ b/lib/deploygate/version.rb @@ -1,3 +1,3 @@ module DeployGate - VERSION = "0.2.3" + VERSION = "0.3.0" end