Class: Everywhere::MobileConfigEndpoint

Inherits:
Object
  • Object
show all
Defined in:
lib/everywhere/mobile_config_endpoint.rb

Overview

Rack middleware serving the mobile shells' remote path configuration:

GET /everywhere/ios_v1.json      (android_v1.json when that shell lands)

The JSON is built from config/everywhere.yml on each request (it's a tiny file, and re-reading means tab changes deploy with the app — the whole point: no app-store release to change tabs). This middleware is the SINATRA/HANAMI strategy — add it to config.ru:

use Everywhere::MobileConfigEndpoint

Rails apps don't need it: Everywhere::Engine appends a real route to MobileConfigsController instead (logging, instrumentation, overridable).

The native shells load it as a Hotwire Native path-configuration source (after their bundled copy), so both rules and settings.tabs can be overridden server-side.

Constant Summary collapse

PATH =
%r{\A/everywhere/(ios|android)_v1\.json\z}
RESET =
"/everywhere/reset"
AASA =
"/.well-known/apple-app-site-association"
"/.well-known/assetlinks.json"

Instance Method Summary collapse

Constructor Details

#initialize(app, root: Dir.pwd) ⇒ MobileConfigEndpoint

Returns a new instance of MobileConfigEndpoint.



30
31
32
33
# File 'lib/everywhere/mobile_config_endpoint.rb', line 30

def initialize(app, root: Dir.pwd)
  @app = app
  @root = root
end

Instance Method Details

#call(env) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/everywhere/mobile_config_endpoint.rb', line 35

def call(env)
  # Jump endpoints exist only while `every preview` runs (pass through
  # otherwise, so nothing is reachable on a normal deploy). The leave page
  # is the exception — it's how Jump escapes a previewed app, so it must
  # answer whenever this gem is present.
  if Jump.enabled?
    if env["REQUEST_METHOD"] == "OPTIONS" &&
       [Jump::SESSION_PATH, Jump::MANIFEST_PATH].include?(env["PATH_INFO"])
      return [204, Jump::CORS_HEADERS.dup, []]
    end
    if env["REQUEST_METHOD"] == "POST" && env["PATH_INFO"] == Jump::SESSION_PATH
      return jump_session(env)
    end
    if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == Jump::MANIFEST_PATH
      return jump_manifest(env)
    end
  end
  if env["REQUEST_METHOD"] == "GET" && env["PATH_INFO"] == Jump::LEAVE_PATH
    return html(Everywhere.mobile_jump_leave_html)
  end

  return @app.call(env) unless env["REQUEST_METHOD"] == "GET"

  if env["PATH_INFO"] == RESET
    require "rack/utils"
    to = Rack::Utils.parse_query(env["QUERY_STRING"])["to"]
    return html(Everywhere.mobile_reset_html(to))
  end

  # Deep-linking association files (generated from everywhere.yml). Pass
  # through when not configured so the host app can serve its own.
  if env["PATH_INFO"] == AASA
    body = Config.load(@root).apple_app_site_association_json
    return body ? json(body) : @app.call(env)
  end
  if env["PATH_INFO"] == ASSETLINKS
    body = Config.load(@root).asset_links_json
    return body ? json(body) : @app.call(env)
  end

  match = PATH.match(env["PATH_INFO"]) or return @app.call(env)

  os = match[1]
  config = Config.load(@root)
  tabs = Everywhere.resolve_tabs(config.tabs_for(os), request_for(env))
  tabs = Jump.exit_tabs(config, os, tabs) if Jump.enabled?
  json(config.path_configuration_json(os, tabs: tabs))
end