diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cc7746e5..15a8cc99 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -21,9 +21,12 @@ class ApplicationController < ActionController::Base class AccessDenied < StandardError; end rescue_from AccessDenied, with: :on_access_denied + rescue_from Async::Stop, Async::Container::Terminate, with: :on_request_stopped + rescue_from ActiveRecord::ConnectionTimeoutError, with: :on_db_timeout + def authenticate_user! redirect_to(new_auth_user_session_path) unless user_signed_in? end @@ -65,6 +68,11 @@ class ApplicationController < ActionController::Base status: :internal_server_error end + def on_db_timeout + render file: 'public/503.html', layout: false, + status: :service_unavailable + end + def redirect_back!(default=:back) redirect_to(params[:return_to] || default) end diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb index cf56452b..fe390949 100644 --- a/app/controllers/items_controller.rb +++ b/app/controllers/items_controller.rb @@ -215,7 +215,8 @@ class ItemsController < ApplicationController @item.compatible_pet_types. preferring_species(cookies["preferred-preview-species-id"] || ""). preferring_color(cookies["preferred-preview-color-id"] || ""). - preferring_simple.first + preferring_simple.first || + PetType.matching_name("Blue", "Acara").first! end def validate_preview diff --git a/app/models/pet.rb b/app/models/pet.rb index a4aa5214..540a37a3 100644 --- a/app/models/pet.rb +++ b/app/models/pet.rb @@ -168,7 +168,7 @@ class Pet < ApplicationRecord # Return the response body as a `HashWithIndifferentAccess`. def self.send_amfphp_request(request, timeout: 10) begin - response = request.post(timeout: timeout, headers: { + response_data = request.post(timeout: timeout, headers: { "User-Agent" => Rails.configuration.user_agent_for_neopets, }) rescue RocketAMFExtensions::RemoteGateway::AMFError => e @@ -177,7 +177,7 @@ class Pet < ApplicationRecord raise DownloadError, e.message, e.backtrace end - HashWithIndifferentAccess.new(response.messages[0].data.body) + HashWithIndifferentAccess.new(response_data) end end diff --git a/app/services/nc_mall.rb b/app/services/nc_mall.rb index 9c914af3..e42df5d0 100644 --- a/app/services/nc_mall.rb +++ b/app/services/nc_mall.rb @@ -76,11 +76,20 @@ module NCMall raise UnexpectedResponseFormat, "missing field object_data in NC page" end + object_data = nc_page["object_data"] + # NOTE: When there's no object data, it will be an empty array instead of # an empty hash. Weird API thing to work around! - nc_page["object_data"] = {} if nc_page["object_data"] == [] + object_data = {} if object_data == [] - items = nc_page["object_data"].values.map do |item_info| + # Only the items in the `render` list are actually listed as directly for + # sale in the shop. `object_data` might contain other items that provide + # supporting information about them, but aren't actually for sale. + visible_object_data = (nc_page["render"] || []). + map { |id| object_data[id.to_s] }. + filter(&:present?) + + items = visible_object_data.map do |item_info| { id: item_info["id"], name: item_info["name"], diff --git a/lib/rocketamf_extensions/remote_gateway/request.rb b/lib/rocketamf_extensions/remote_gateway/request.rb index d102b6c3..9adde85a 100644 --- a/lib/rocketamf_extensions/remote_gateway/request.rb +++ b/lib/rocketamf_extensions/remote_gateway/request.rb @@ -54,7 +54,25 @@ module RocketAMFExtensions raise RocketAMF::AMFError.new(first_message_data) end - result + # HACK: It seems to me that these messages come back with Windows-1250 + # (or similar) encoding on the strings? I'm basing this on the + # Patchwork Staff item, whose description arrives as: + # + # "That staff is cute, but dont use it as a walking stick \x96 I " + + # "dont think it will hold you up!" + # + # And the `\x96` is meant to represent an endash, which it doesn't in + # UTF-8 or in most extended ASCII encodings, but *does* in Windows's + # specific extended ASCII. + # + # Idk if this is something to do with the AMFPHP spec or how the AMFPHP + # server code they use serializes strings (I couldn't find any + # reference to it?), or just their internal database encoding being + # passed along as-is, or what? But this seems to be the most correct + # interpretation I know how to do, so, let's do it! + result.messages[0].data.body.tap do |body| + reencode_strings! body, "Windows-1250", "UTF-8" + end end private @@ -86,6 +104,16 @@ module RocketAMFExtensions raise ConnectionError, e.message end end + + def reencode_strings!(target, from, to) + if target.is_a? String + target.force_encoding(from).encode!(to) + elsif target.is_a? Array + target.each { |x| reencode_strings!(x, from, to) } + elsif target.is_a? Hash + target.values.each { |x| reencode_strings!(x, from, to) } + end + end end class ConnectionError < RuntimeError diff --git a/public/503.html b/public/503.html new file mode 100644 index 00000000..ac499199 --- /dev/null +++ b/public/503.html @@ -0,0 +1,59 @@ + + + + + + Dress to Impress: Whelmy mode! + + + +
+ Distressed Grundo programmer +
+

DTI is overloaded!

+

+ There's a lot going on in our server right now… usually this lasts for + a few seconds, then passes? Sorry about this! +

+

+ If this keeps happening, we'll be alerted automatically, and we'll do + our best to get it fixed up 💖 +

+
+
+ +