@cendarsoss/pusher-js 8.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +14 -0
- package/.github/ISSUE_TEMPLATE.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/.github/dependabot.yml +14 -0
- package/.github/stale.yml +26 -0
- package/.github/workflows/release.yml +112 -0
- package/.github/workflows/release_pr.yml +43 -0
- package/.github/workflows/run-tests.yml +62 -0
- package/.gitmodules +3 -0
- package/.prettierrc +2 -0
- package/CHANGELOG.md +928 -0
- package/DELTA_COMPRESSION.md +365 -0
- package/DELTA_USAGE.md +179 -0
- package/IMPLEMENTATION_SUMMARY.md +261 -0
- package/IMPORT_GUIDE.md +638 -0
- package/LIBRARY_STRUCTURE_ANALYSIS.md +940 -0
- package/LICENCE +19 -0
- package/Makefile +14 -0
- package/README.md +709 -0
- package/TAG_FILTERING_CLIENT.md +471 -0
- package/bower.json +19 -0
- package/bun.lock +2695 -0
- package/dist/node/filter.js +252 -0
- package/dist/node/filter.js.map +1 -0
- package/dist/node/pusher.js +4434 -0
- package/dist/node/pusher.js.map +1 -0
- package/dist/web/filter.mjs +252 -0
- package/dist/web/filter.mjs.map +1 -0
- package/dist/web/pusher.mjs +5889 -0
- package/dist/web/pusher.mjs.map +1 -0
- package/examples/delta-compression-example.html +372 -0
- package/examples/delta-seamless-example.html +185 -0
- package/index.d.ts +36 -0
- package/integration_tests_server/index.js +176 -0
- package/integration_tests_server/package-lock.json +1177 -0
- package/integration_tests_server/package.json +15 -0
- package/interactive/.env +16 -0
- package/interactive/CONFLATION_TEST.md +73 -0
- package/interactive/DELTA_COMPRESSION_TESTING.md +262 -0
- package/interactive/bun.lock +208 -0
- package/interactive/package-lock.json +1075 -0
- package/interactive/package.json +32 -0
- package/interactive/public/app.js +1363 -0
- package/interactive/public/bundle-entry.js +14 -0
- package/interactive/public/conflation-test.html +508 -0
- package/interactive/public/conflation-test.js +785 -0
- package/interactive/public/delta-compression.js +1090 -0
- package/interactive/public/dist/bundle.js +5857 -0
- package/interactive/public/index.html +392 -0
- package/interactive/public/main.js +20 -0
- package/interactive/public/style.css +823 -0
- package/interactive/server.js +246 -0
- package/interactive/test-bundle.html +89 -0
- package/interactive/test-delta.js +146 -0
- package/node.js +1 -0
- package/package.json +94 -0
- package/pusher-with-encryption/index.js +1 -0
- package/react-native/index.d.ts +29 -0
- package/react-native/index.js +1 -0
- package/spec/config/jasmine/helpers/reporter.js +14 -0
- package/spec/config/jasmine/integration.json +13 -0
- package/spec/config/jasmine/unit.json +13 -0
- package/spec/config/jasmine/webpack.integration.js +33 -0
- package/spec/config/jasmine/webpack.unit.js +30 -0
- package/spec/config/karma/available_browsers.json +4957 -0
- package/spec/config/karma/config.ci.js +25 -0
- package/spec/config/karma/config.common.js +50 -0
- package/spec/config/karma/config.integration.js +26 -0
- package/spec/config/karma/config.unit.js +10 -0
- package/spec/config/karma/config.worker.js +34 -0
- package/spec/config/karma/integration.js +24 -0
- package/spec/config/karma/unit.js +20 -0
- package/spec/javascripts/helpers/mocks.js +274 -0
- package/spec/javascripts/helpers/node/integration.js +33 -0
- package/spec/javascripts/helpers/node/mock-dom-dependencies.ts +1 -0
- package/spec/javascripts/helpers/pusher_integration.js +1 -0
- package/spec/javascripts/helpers/pusher_integration_class.ts +12 -0
- package/spec/javascripts/helpers/timers/promises.js +9 -0
- package/spec/javascripts/helpers/waitsFor.js +37 -0
- package/spec/javascripts/helpers/web/integration.js +44 -0
- package/spec/javascripts/helpers/worker/mock-dom-dependencies.js +1 -0
- package/spec/javascripts/integration/core/cluster_config_spec.js +153 -0
- package/spec/javascripts/integration/core/falling_back_spec.js +195 -0
- package/spec/javascripts/integration/core/pusher_spec/index.js +68 -0
- package/spec/javascripts/integration/core/pusher_spec/test_builder.js +715 -0
- package/spec/javascripts/integration/core/timeout_configuration_spec.js +200 -0
- package/spec/javascripts/integration/core/transport_lists_spec.js +103 -0
- package/spec/javascripts/integration/index.node.js +12 -0
- package/spec/javascripts/integration/index.web.js +63 -0
- package/spec/javascripts/integration/index.worker.js +13 -0
- package/spec/javascripts/integration/web/dom/jsonp_spec.js +97 -0
- package/spec/javascripts/integration/web/dom/script_request_spec.js +90 -0
- package/spec/javascripts/polyfills/index.js +105 -0
- package/spec/javascripts/unit/core/channels/channel_spec.js +355 -0
- package/spec/javascripts/unit/core/channels/channels_spec.js +94 -0
- package/spec/javascripts/unit/core/channels/encrypted_channel_spec.js +343 -0
- package/spec/javascripts/unit/core/channels/presence_channel_spec.js +553 -0
- package/spec/javascripts/unit/core/channels/private_channel_spec.js +182 -0
- package/spec/javascripts/unit/core/config_spec.js +507 -0
- package/spec/javascripts/unit/core/connection/connection_manager_spec.js +656 -0
- package/spec/javascripts/unit/core/connection/connection_spec.js +286 -0
- package/spec/javascripts/unit/core/connection/handshake_spec.js +160 -0
- package/spec/javascripts/unit/core/connection/protocol_spec.js +420 -0
- package/spec/javascripts/unit/core/defaults_spec.js +26 -0
- package/spec/javascripts/unit/core/events_dispatcher_spec.js +385 -0
- package/spec/javascripts/unit/core/http/http_polling_socket_spec.js +60 -0
- package/spec/javascripts/unit/core/http/http_request_spec.js +185 -0
- package/spec/javascripts/unit/core/http/http_socket_spec.js +370 -0
- package/spec/javascripts/unit/core/http/http_streaming_socket_spec.js +56 -0
- package/spec/javascripts/unit/core/http/http_xhr_request_spec.js +164 -0
- package/spec/javascripts/unit/core/logger_spec.js +133 -0
- package/spec/javascripts/unit/core/pusher_spec.js +613 -0
- package/spec/javascripts/unit/core/pusher_with_encryption_spec.js +18 -0
- package/spec/javascripts/unit/core/strategies/best_connected_ever_strategy_spec.js +104 -0
- package/spec/javascripts/unit/core/strategies/delayed_strategy_spec.js +95 -0
- package/spec/javascripts/unit/core/strategies/first_connected_strategy_spec.js +68 -0
- package/spec/javascripts/unit/core/strategies/if_strategy_spec.js +165 -0
- package/spec/javascripts/unit/core/strategies/sequential_strategy_spec.js +213 -0
- package/spec/javascripts/unit/core/strategies/transport_strategy_spec.js +250 -0
- package/spec/javascripts/unit/core/strategies/websocket_prioritized_cached_strategy_spec.js +400 -0
- package/spec/javascripts/unit/core/timeline/timeline_spec.js +153 -0
- package/spec/javascripts/unit/core/transports/assistant_to_the_transport_manager_spec.js +223 -0
- package/spec/javascripts/unit/core/transports/hosts_and_ports_spec.js +85 -0
- package/spec/javascripts/unit/core/transports/transport_connection_spec.js +585 -0
- package/spec/javascripts/unit/core/transports/transport_manager_spec.js +64 -0
- package/spec/javascripts/unit/core/user_spec.js +303 -0
- package/spec/javascripts/unit/core/utils/periodic_timer_spec.js +74 -0
- package/spec/javascripts/unit/core/utils/timers_spec.js +157 -0
- package/spec/javascripts/unit/core/utils/url_store_spec.js +14 -0
- package/spec/javascripts/unit/core/watchlist_spec.js +48 -0
- package/spec/javascripts/unit/core_with_runtime/auth/channel_authorizer_spec.js +137 -0
- package/spec/javascripts/unit/core_with_runtime/auth/deprecated_channel_authorizer_spec.js +48 -0
- package/spec/javascripts/unit/core_with_runtime/auth/user_authorizer_spec.js +128 -0
- package/spec/javascripts/unit/core_with_runtime/readme.md +5 -0
- package/spec/javascripts/unit/index.node.js +11 -0
- package/spec/javascripts/unit/index.web.js +12 -0
- package/spec/javascripts/unit/index.worker.js +11 -0
- package/spec/javascripts/unit/isomorphic/transports/hosts_and_ports_spec.js +82 -0
- package/spec/javascripts/unit/isomorphic/transports/transports_spec.js +202 -0
- package/spec/javascripts/unit/node/timeline_sender_spec.js +83 -0
- package/spec/javascripts/unit/web/dom/dependency_loader_spec.js +249 -0
- package/spec/javascripts/unit/web/dom/jsonp_request_spec.js +130 -0
- package/spec/javascripts/unit/web/dom/script_receiver_factory_spec.js +68 -0
- package/spec/javascripts/unit/web/http/http_xdomain_request_spec.js +222 -0
- package/spec/javascripts/unit/web/pusher_authorizer_spec.js +64 -0
- package/spec/javascripts/unit/web/timeline/timeline_sender_spec.js +131 -0
- package/spec/javascripts/unit/web/transports/hosts_and_ports_spec.js +127 -0
- package/spec/javascripts/unit/web/transports/transports_spec.js +444 -0
- package/spec/javascripts/unit/worker/channel_authorizer_spec.js +156 -0
- package/spec/javascripts/unit/worker/timeline_sender_spec.js +76 -0
- package/src/core/auth/auth_transports.ts +18 -0
- package/src/core/auth/channel_authorizer.ts +64 -0
- package/src/core/auth/deprecated_channel_authorizer.ts +56 -0
- package/src/core/auth/options.ts +76 -0
- package/src/core/auth/user_authenticator.ts +62 -0
- package/src/core/base64.ts +49 -0
- package/src/core/channels/channel.ts +173 -0
- package/src/core/channels/channel_table.ts +7 -0
- package/src/core/channels/channels.ts +86 -0
- package/src/core/channels/encrypted_channel.ts +150 -0
- package/src/core/channels/filter.ts +342 -0
- package/src/core/channels/members.ts +80 -0
- package/src/core/channels/metadata.ts +5 -0
- package/src/core/channels/presence_channel.ts +113 -0
- package/src/core/channels/private_channel.ts +25 -0
- package/src/core/config.ts +189 -0
- package/src/core/connection/callbacks.ts +21 -0
- package/src/core/connection/connection.ts +160 -0
- package/src/core/connection/connection_manager.ts +371 -0
- package/src/core/connection/connection_manager_options.ts +14 -0
- package/src/core/connection/handshake/handshake_payload.ts +10 -0
- package/src/core/connection/handshake/index.ts +90 -0
- package/src/core/connection/protocol/action.ts +8 -0
- package/src/core/connection/protocol/message-types.ts +11 -0
- package/src/core/connection/protocol/protocol.ts +166 -0
- package/src/core/defaults.ts +66 -0
- package/src/core/delta/channel_state.ts +194 -0
- package/src/core/delta/decoders.ts +129 -0
- package/src/core/delta/index.ts +10 -0
- package/src/core/delta/manager.ts +504 -0
- package/src/core/delta/types.ts +60 -0
- package/src/core/errors.ts +69 -0
- package/src/core/events/callback.ts +6 -0
- package/src/core/events/callback_registry.ts +75 -0
- package/src/core/events/callback_table.ts +7 -0
- package/src/core/events/dispatcher.ts +84 -0
- package/src/core/http/ajax.ts +24 -0
- package/src/core/http/http_factory.ts +16 -0
- package/src/core/http/http_polling_socket.ts +24 -0
- package/src/core/http/http_request.ts +81 -0
- package/src/core/http/http_socket.ts +220 -0
- package/src/core/http/http_streaming_socket.ts +19 -0
- package/src/core/http/request_hooks.ts +9 -0
- package/src/core/http/socket_hooks.ts +11 -0
- package/src/core/http/state.ts +7 -0
- package/src/core/http/url_location.ts +6 -0
- package/src/core/logger.ts +66 -0
- package/src/core/options.ts +61 -0
- package/src/core/pusher-licence.js +7 -0
- package/src/core/pusher-with-encryption.js +1 -0
- package/src/core/pusher-with-encryption.ts +14 -0
- package/src/core/pusher.js +10 -0
- package/src/core/pusher.ts +412 -0
- package/src/core/reachability.ts +7 -0
- package/src/core/socket.ts +14 -0
- package/src/core/strategies/best_connected_ever_strategy.ts +81 -0
- package/src/core/strategies/delayed_strategy.ts +48 -0
- package/src/core/strategies/first_connected_strategy.ts +31 -0
- package/src/core/strategies/if_strategy.ts +34 -0
- package/src/core/strategies/sequential_strategy.ts +129 -0
- package/src/core/strategies/strategy.ts +8 -0
- package/src/core/strategies/strategy_builder.ts +67 -0
- package/src/core/strategies/strategy_options.ts +18 -0
- package/src/core/strategies/strategy_runner.ts +6 -0
- package/src/core/strategies/transport_strategy.ts +144 -0
- package/src/core/strategies/websocket_prioritized_cached_strategy.ts +157 -0
- package/src/core/timeline/level.ts +7 -0
- package/src/core/timeline/timeline.ts +90 -0
- package/src/core/timeline/timeline_sender.ts +33 -0
- package/src/core/timeline/timeline_transport.ts +11 -0
- package/src/core/transports/assistant_to_the_transport_manager.ts +104 -0
- package/src/core/transports/ping_delay_options.ts +7 -0
- package/src/core/transports/transport.ts +54 -0
- package/src/core/transports/transport_connection.ts +241 -0
- package/src/core/transports/transport_connection_options.ts +8 -0
- package/src/core/transports/transport_hooks.ts +16 -0
- package/src/core/transports/transport_manager.ts +52 -0
- package/src/core/transports/transports_table.ts +12 -0
- package/src/core/transports/url_scheme.ts +13 -0
- package/src/core/transports/url_schemes.ts +47 -0
- package/src/core/user.ts +186 -0
- package/src/core/util.ts +34 -0
- package/src/core/utils/collections.ts +353 -0
- package/src/core/utils/factory.ts +79 -0
- package/src/core/utils/flat_promise.ts +10 -0
- package/src/core/utils/timers/abstract_timer.ts +39 -0
- package/src/core/utils/timers/index.ts +39 -0
- package/src/core/utils/timers/scheduling.ts +11 -0
- package/src/core/utils/timers/timed_callback.ts +5 -0
- package/src/core/utils/url_store.ts +48 -0
- package/src/core/watchlist.ts +31 -0
- package/src/d.ts/constants/index.d.ts +5 -0
- package/src/d.ts/faye-websocket/faye-websocket.d.ts +21 -0
- package/src/d.ts/global/global.d.ts +1 -0
- package/src/d.ts/module/module.d.ts +12 -0
- package/src/d.ts/tweetnacl-util/index.d.ts +6 -0
- package/src/d.ts/window/events.d.ts +4 -0
- package/src/d.ts/window/sockjs.d.ts +3 -0
- package/src/d.ts/window/websocket.d.ts +4 -0
- package/src/d.ts/window/xmlhttprequest.d.ts +3 -0
- package/src/filter.ts +5 -0
- package/src/index.ts +8 -0
- package/src/runtimes/interface.ts +60 -0
- package/src/runtimes/isomorphic/auth/xhr_auth.ts +90 -0
- package/src/runtimes/isomorphic/default_strategy.ts +155 -0
- package/src/runtimes/isomorphic/http/http.ts +32 -0
- package/src/runtimes/isomorphic/http/http_xhr_request.ts +35 -0
- package/src/runtimes/isomorphic/runtime.ts +62 -0
- package/src/runtimes/isomorphic/timeline/xhr_timeline.ts +50 -0
- package/src/runtimes/isomorphic/transports/transport_connection_initializer.ts +19 -0
- package/src/runtimes/isomorphic/transports/transports.ts +83 -0
- package/src/runtimes/node/net_info.ts +10 -0
- package/src/runtimes/node/runtime.ts +68 -0
- package/src/runtimes/react-native/net_info.ts +42 -0
- package/src/runtimes/react-native/runtime.ts +65 -0
- package/src/runtimes/web/auth/jsonp_auth.ts +51 -0
- package/src/runtimes/web/browser.ts +24 -0
- package/src/runtimes/web/default_strategy.ts +201 -0
- package/src/runtimes/web/dom/dependencies.ts +16 -0
- package/src/runtimes/web/dom/dependency_loader.ts +93 -0
- package/src/runtimes/web/dom/json2.js +486 -0
- package/src/runtimes/web/dom/jsonp_request.ts +52 -0
- package/src/runtimes/web/dom/script_receiver.ts +8 -0
- package/src/runtimes/web/dom/script_receiver_factory.ts +57 -0
- package/src/runtimes/web/dom/script_request.ts +85 -0
- package/src/runtimes/web/http/http.ts +8 -0
- package/src/runtimes/web/http/http_xdomain_request.ts +37 -0
- package/src/runtimes/web/net_info.ts +50 -0
- package/src/runtimes/web/runtime.ts +174 -0
- package/src/runtimes/web/timeline/jsonp_timeline.ts +34 -0
- package/src/runtimes/web/transports/transport_connection_initializer.ts +39 -0
- package/src/runtimes/web/transports/transports.ts +67 -0
- package/src/runtimes/worker/auth/fetch_auth.ts +69 -0
- package/src/runtimes/worker/net_info.ts +10 -0
- package/src/runtimes/worker/runtime.ts +75 -0
- package/src/runtimes/worker/timeline/fetch_timeline.ts +39 -0
- package/tsconfig.json +18 -0
- package/types/spec/javascripts/helpers/node/mock-dom-dependencies.d.ts +1 -0
- package/types/spec/javascripts/helpers/pusher_integration_class.d.ts +4 -0
- package/types/src/core/auth/auth_transports.d.ts +9 -0
- package/types/src/core/auth/channel_authorizer.d.ts +3 -0
- package/types/src/core/auth/deprecated_channel_authorizer.d.ts +18 -0
- package/types/src/core/auth/options.d.ts +48 -0
- package/types/src/core/auth/user_authenticator.d.ts +3 -0
- package/types/src/core/base64.d.ts +1 -0
- package/types/src/core/channels/channel.d.ts +25 -0
- package/types/src/core/channels/channel_table.d.ts +5 -0
- package/types/src/core/channels/channels.d.ts +12 -0
- package/types/src/core/channels/encrypted_channel.d.ts +15 -0
- package/types/src/core/channels/filter.d.ts +33 -0
- package/types/src/core/channels/members.d.ts +14 -0
- package/types/src/core/channels/metadata.d.ts +4 -0
- package/types/src/core/channels/presence_channel.d.ts +13 -0
- package/types/src/core/channels/private_channel.d.ts +5 -0
- package/types/src/core/config.d.ts +31 -0
- package/types/src/core/connection/callbacks.d.ts +18 -0
- package/types/src/core/connection/connection.d.ts +16 -0
- package/types/src/core/connection/connection_manager.d.ts +50 -0
- package/types/src/core/connection/connection_manager_options.d.ts +11 -0
- package/types/src/core/connection/handshake/handshake_payload.d.ts +8 -0
- package/types/src/core/connection/handshake/index.d.ts +12 -0
- package/types/src/core/connection/protocol/action.d.ts +7 -0
- package/types/src/core/connection/protocol/message-types.d.ts +10 -0
- package/types/src/core/connection/protocol/protocol.d.ts +10 -0
- package/types/src/core/defaults.d.ts +26 -0
- package/types/src/core/delta/channel_state.d.ts +23 -0
- package/types/src/core/delta/decoders.d.ts +12 -0
- package/types/src/core/delta/index.d.ts +4 -0
- package/types/src/core/delta/manager.d.ts +27 -0
- package/types/src/core/delta/types.d.ts +50 -0
- package/types/src/core/errors.d.ts +28 -0
- package/types/src/core/events/callback.d.ts +5 -0
- package/types/src/core/events/callback_registry.d.ts +11 -0
- package/types/src/core/events/callback_table.d.ts +5 -0
- package/types/src/core/events/dispatcher.d.ts +14 -0
- package/types/src/core/http/ajax.d.ts +16 -0
- package/types/src/core/http/http_factory.d.ts +13 -0
- package/types/src/core/http/http_polling_socket.d.ts +3 -0
- package/types/src/core/http/http_request.d.ts +17 -0
- package/types/src/core/http/http_socket.d.ts +32 -0
- package/types/src/core/http/http_streaming_socket.d.ts +3 -0
- package/types/src/core/http/request_hooks.d.ts +6 -0
- package/types/src/core/http/socket_hooks.d.ts +8 -0
- package/types/src/core/http/state.d.ts +6 -0
- package/types/src/core/http/url_location.d.ts +5 -0
- package/types/src/core/logger.d.ts +11 -0
- package/types/src/core/options.d.ts +36 -0
- package/types/src/core/pusher-with-encryption.d.ts +5 -0
- package/types/src/core/pusher.d.ts +56 -0
- package/types/src/core/reachability.d.ts +5 -0
- package/types/src/core/socket.d.ts +12 -0
- package/types/src/core/strategies/best_connected_ever_strategy.d.ts +10 -0
- package/types/src/core/strategies/delayed_strategy.d.ts +15 -0
- package/types/src/core/strategies/first_connected_strategy.d.ts +8 -0
- package/types/src/core/strategies/if_strategy.d.ts +10 -0
- package/types/src/core/strategies/sequential_strategy.d.ts +16 -0
- package/types/src/core/strategies/strategy.d.ts +6 -0
- package/types/src/core/strategies/strategy_builder.d.ts +5 -0
- package/types/src/core/strategies/strategy_options.d.ts +16 -0
- package/types/src/core/strategies/strategy_runner.d.ts +5 -0
- package/types/src/core/strategies/transport_strategy.d.ts +15 -0
- package/types/src/core/strategies/websocket_prioritized_cached_strategy.d.ts +20 -0
- package/types/src/core/timeline/level.d.ts +6 -0
- package/types/src/core/timeline/timeline.d.ts +25 -0
- package/types/src/core/timeline/timeline_sender.d.ts +13 -0
- package/types/src/core/timeline/timeline_transport.d.ts +6 -0
- package/types/src/core/transports/assistant_to_the_transport_manager.d.ts +14 -0
- package/types/src/core/transports/ping_delay_options.d.ts +6 -0
- package/types/src/core/transports/transport.d.ts +8 -0
- package/types/src/core/transports/transport_connection.d.ts +35 -0
- package/types/src/core/transports/transport_connection_options.d.ts +6 -0
- package/types/src/core/transports/transport_hooks.d.ts +13 -0
- package/types/src/core/transports/transport_manager.d.ts +14 -0
- package/types/src/core/transports/transports_table.d.ts +10 -0
- package/types/src/core/transports/url_scheme.d.ts +11 -0
- package/types/src/core/transports/url_schemes.d.ts +4 -0
- package/types/src/core/user.d.ts +21 -0
- package/types/src/core/util.d.ts +8 -0
- package/types/src/core/utils/collections.d.ts +18 -0
- package/types/src/core/utils/factory.d.ts +29 -0
- package/types/src/core/utils/flat_promise.d.ts +6 -0
- package/types/src/core/utils/timers/abstract_timer.d.ts +10 -0
- package/types/src/core/utils/timers/index.d.ts +9 -0
- package/types/src/core/utils/timers/scheduling.d.ts +8 -0
- package/types/src/core/utils/timers/timed_callback.d.ts +4 -0
- package/types/src/core/utils/url_store.d.ts +4 -0
- package/types/src/core/watchlist.d.ts +8 -0
- package/types/src/runtimes/interface.d.ts +43 -0
- package/types/src/runtimes/isomorphic/auth/xhr_auth.d.ts +3 -0
- package/types/src/runtimes/isomorphic/default_strategy.d.ts +5 -0
- package/types/src/runtimes/isomorphic/http/http.d.ts +3 -0
- package/types/src/runtimes/isomorphic/http/http_xhr_request.d.ts +3 -0
- package/types/src/runtimes/isomorphic/runtime.d.ts +2 -0
- package/types/src/runtimes/isomorphic/timeline/xhr_timeline.d.ts +6 -0
- package/types/src/runtimes/isomorphic/transports/transport_connection_initializer.d.ts +1 -0
- package/types/src/runtimes/isomorphic/transports/transports.d.ts +5 -0
- package/types/src/runtimes/node/net_info.d.ts +6 -0
- package/types/src/runtimes/node/runtime.d.ts +3 -0
- package/types/src/runtimes/react-native/net_info.d.ts +8 -0
- package/types/src/runtimes/react-native/runtime.d.ts +3 -0
- package/types/src/runtimes/web/auth/jsonp_auth.d.ts +3 -0
- package/types/src/runtimes/web/browser.d.ts +19 -0
- package/types/src/runtimes/web/default_strategy.d.ts +5 -0
- package/types/src/runtimes/web/dom/dependencies.d.ts +4 -0
- package/types/src/runtimes/web/dom/dependency_loader.d.ts +10 -0
- package/types/src/runtimes/web/dom/jsonp_request.d.ts +10 -0
- package/types/src/runtimes/web/dom/script_receiver.d.ts +7 -0
- package/types/src/runtimes/web/dom/script_receiver_factory.d.ts +10 -0
- package/types/src/runtimes/web/dom/script_request.d.ts +9 -0
- package/types/src/runtimes/web/http/http.d.ts +2 -0
- package/types/src/runtimes/web/http/http_xdomain_request.d.ts +3 -0
- package/types/src/runtimes/web/net_info.d.ts +7 -0
- package/types/src/runtimes/web/runtime.d.ts +3 -0
- package/types/src/runtimes/web/timeline/jsonp_timeline.d.ts +6 -0
- package/types/src/runtimes/web/transports/transport_connection_initializer.d.ts +1 -0
- package/types/src/runtimes/web/transports/transports.d.ts +2 -0
- package/types/src/runtimes/worker/auth/fetch_auth.d.ts +3 -0
- package/types/src/runtimes/worker/net_info.d.ts +6 -0
- package/types/src/runtimes/worker/runtime.d.ts +3 -0
- package/types/src/runtimes/worker/timeline/fetch_timeline.d.ts +6 -0
- package/vite.config.js +52 -0
- package/vite.config.node.js +72 -0
- package/webpack/config.node.js +26 -0
- package/webpack/config.react-native.js +35 -0
- package/webpack/config.shared.js +50 -0
- package/webpack/config.web.js +36 -0
- package/webpack/config.worker.js +42 -0
- package/webpack/dev.server.js +17 -0
- package/webpack/hosting_config.js +6 -0
- package/with-encryption/index.d.ts +29 -0
- package/with-encryption/index.js +4 -0
- package/worker/index.d.ts +29 -0
- package/worker/index.js +1 -0
- package/worker/with-encryption/index.d.ts +29 -0
- package/worker/with-encryption/index.js +1 -0
|
@@ -0,0 +1,4434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const utf8 = require("@stablelib/utf8");
|
|
3
|
+
const base64 = require("@stablelib/base64");
|
|
4
|
+
const fayeWebsocket = require("faye-websocket");
|
|
5
|
+
const xmlhttprequest = require("xmlhttprequest");
|
|
6
|
+
const crypto = require("crypto");
|
|
7
|
+
const fossilDelta = require("fossil-delta");
|
|
8
|
+
const vcdiffDecoder = require("@ably/vcdiff-decoder");
|
|
9
|
+
function encode(s) {
|
|
10
|
+
return btoa(utob(s));
|
|
11
|
+
}
|
|
12
|
+
var fromCharCode = String.fromCharCode;
|
|
13
|
+
var b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
14
|
+
var cb_utob = function(c) {
|
|
15
|
+
var cc = c.charCodeAt(0);
|
|
16
|
+
return cc < 128 ? c : cc < 2048 ? fromCharCode(192 | cc >>> 6) + fromCharCode(128 | cc & 63) : fromCharCode(224 | cc >>> 12 & 15) + fromCharCode(128 | cc >>> 6 & 63) + fromCharCode(128 | cc & 63);
|
|
17
|
+
};
|
|
18
|
+
var utob = function(u) {
|
|
19
|
+
return u.replace(/[^\x00-\x7F]/g, cb_utob);
|
|
20
|
+
};
|
|
21
|
+
var cb_encode = function(ccc) {
|
|
22
|
+
var padlen = [0, 2, 1][ccc.length % 3];
|
|
23
|
+
var ord = ccc.charCodeAt(0) << 16 | (ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8 | (ccc.length > 2 ? ccc.charCodeAt(2) : 0);
|
|
24
|
+
var chars = [
|
|
25
|
+
b64chars.charAt(ord >>> 18),
|
|
26
|
+
b64chars.charAt(ord >>> 12 & 63),
|
|
27
|
+
padlen >= 2 ? "=" : b64chars.charAt(ord >>> 6 & 63),
|
|
28
|
+
padlen >= 1 ? "=" : b64chars.charAt(ord & 63)
|
|
29
|
+
];
|
|
30
|
+
return chars.join("");
|
|
31
|
+
};
|
|
32
|
+
var btoa = global.btoa || function(b) {
|
|
33
|
+
return b.replace(/[\s\S]{1,3}/g, cb_encode);
|
|
34
|
+
};
|
|
35
|
+
class Timer {
|
|
36
|
+
constructor(set, clear, delay, callback) {
|
|
37
|
+
this.clear = clear;
|
|
38
|
+
this.timer = set(() => {
|
|
39
|
+
if (this.timer) {
|
|
40
|
+
this.timer = callback(this.timer);
|
|
41
|
+
}
|
|
42
|
+
}, delay);
|
|
43
|
+
}
|
|
44
|
+
/** Returns whether the timer is still running.
|
|
45
|
+
*
|
|
46
|
+
* @return {Boolean}
|
|
47
|
+
*/
|
|
48
|
+
isRunning() {
|
|
49
|
+
return this.timer !== null;
|
|
50
|
+
}
|
|
51
|
+
/** Aborts a timer when it's running. */
|
|
52
|
+
ensureAborted() {
|
|
53
|
+
if (this.timer) {
|
|
54
|
+
this.clear(this.timer);
|
|
55
|
+
this.timer = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function clearTimeout(timer) {
|
|
60
|
+
global.clearTimeout(timer);
|
|
61
|
+
}
|
|
62
|
+
function clearInterval(timer) {
|
|
63
|
+
global.clearInterval(timer);
|
|
64
|
+
}
|
|
65
|
+
class OneOffTimer extends Timer {
|
|
66
|
+
constructor(delay, callback) {
|
|
67
|
+
super(setTimeout, clearTimeout, delay, function(timer) {
|
|
68
|
+
callback();
|
|
69
|
+
return null;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
class PeriodicTimer extends Timer {
|
|
74
|
+
constructor(delay, callback) {
|
|
75
|
+
super(setInterval, clearInterval, delay, function(timer) {
|
|
76
|
+
callback();
|
|
77
|
+
return timer;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
var Util = {
|
|
82
|
+
now() {
|
|
83
|
+
if (Date.now) {
|
|
84
|
+
return Date.now();
|
|
85
|
+
} else {
|
|
86
|
+
return (/* @__PURE__ */ new Date()).valueOf();
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
defer(callback) {
|
|
90
|
+
return new OneOffTimer(0, callback);
|
|
91
|
+
},
|
|
92
|
+
/** Builds a function that will proxy a method call to its first argument.
|
|
93
|
+
*
|
|
94
|
+
* Allows partial application of arguments, so additional arguments are
|
|
95
|
+
* prepended to the argument list.
|
|
96
|
+
*
|
|
97
|
+
* @param {String} name method name
|
|
98
|
+
* @return {Function} proxy function
|
|
99
|
+
*/
|
|
100
|
+
method(name, ...args) {
|
|
101
|
+
var boundArguments = Array.prototype.slice.call(arguments, 1);
|
|
102
|
+
return function(object) {
|
|
103
|
+
return object[name].apply(object, boundArguments.concat(arguments));
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
function extend(target, ...sources) {
|
|
108
|
+
for (var i = 0; i < sources.length; i++) {
|
|
109
|
+
var extensions = sources[i];
|
|
110
|
+
for (var property in extensions) {
|
|
111
|
+
if (extensions[property] && extensions[property].constructor && extensions[property].constructor === Object) {
|
|
112
|
+
target[property] = extend(target[property] || {}, extensions[property]);
|
|
113
|
+
} else {
|
|
114
|
+
target[property] = extensions[property];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return target;
|
|
119
|
+
}
|
|
120
|
+
function stringify() {
|
|
121
|
+
var m = ["Pusher"];
|
|
122
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
123
|
+
if (typeof arguments[i] === "string") {
|
|
124
|
+
m.push(arguments[i]);
|
|
125
|
+
} else {
|
|
126
|
+
m.push(safeJSONStringify(arguments[i]));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return m.join(" : ");
|
|
130
|
+
}
|
|
131
|
+
function arrayIndexOf(array, item) {
|
|
132
|
+
var nativeIndexOf = Array.prototype.indexOf;
|
|
133
|
+
if (array === null) {
|
|
134
|
+
return -1;
|
|
135
|
+
}
|
|
136
|
+
if (nativeIndexOf && array.indexOf === nativeIndexOf) {
|
|
137
|
+
return array.indexOf(item);
|
|
138
|
+
}
|
|
139
|
+
for (var i = 0, l = array.length; i < l; i++) {
|
|
140
|
+
if (array[i] === item) {
|
|
141
|
+
return i;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
function objectApply(object, f) {
|
|
147
|
+
for (var key in object) {
|
|
148
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
149
|
+
f(object[key], key, object);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function keys(object) {
|
|
154
|
+
var keys2 = [];
|
|
155
|
+
objectApply(object, function(_, key) {
|
|
156
|
+
keys2.push(key);
|
|
157
|
+
});
|
|
158
|
+
return keys2;
|
|
159
|
+
}
|
|
160
|
+
function values(object) {
|
|
161
|
+
var values2 = [];
|
|
162
|
+
objectApply(object, function(value) {
|
|
163
|
+
values2.push(value);
|
|
164
|
+
});
|
|
165
|
+
return values2;
|
|
166
|
+
}
|
|
167
|
+
function apply(array, f, context) {
|
|
168
|
+
for (var i = 0; i < array.length; i++) {
|
|
169
|
+
f.call(context || global, array[i], i, array);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function map(array, f) {
|
|
173
|
+
var result = [];
|
|
174
|
+
for (var i = 0; i < array.length; i++) {
|
|
175
|
+
result.push(f(array[i], i, array, result));
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
function mapObject(object, f) {
|
|
180
|
+
var result = {};
|
|
181
|
+
objectApply(object, function(value, key) {
|
|
182
|
+
result[key] = f(value);
|
|
183
|
+
});
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
function filter(array, test) {
|
|
187
|
+
test = test || function(value) {
|
|
188
|
+
return !!value;
|
|
189
|
+
};
|
|
190
|
+
var result = [];
|
|
191
|
+
for (var i = 0; i < array.length; i++) {
|
|
192
|
+
if (test(array[i], i, array, result)) {
|
|
193
|
+
result.push(array[i]);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
function filterObject(object, test) {
|
|
199
|
+
var result = {};
|
|
200
|
+
objectApply(object, function(value, key) {
|
|
201
|
+
if (test && test(value, key, object, result) || Boolean(value)) {
|
|
202
|
+
result[key] = value;
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
function flatten(object) {
|
|
208
|
+
var result = [];
|
|
209
|
+
objectApply(object, function(value, key) {
|
|
210
|
+
result.push([key, value]);
|
|
211
|
+
});
|
|
212
|
+
return result;
|
|
213
|
+
}
|
|
214
|
+
function any(array, test) {
|
|
215
|
+
for (var i = 0; i < array.length; i++) {
|
|
216
|
+
if (test(array[i], i, array)) {
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
function all(array, test) {
|
|
223
|
+
for (var i = 0; i < array.length; i++) {
|
|
224
|
+
if (!test(array[i], i, array)) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
function encodeParamsObject(data) {
|
|
231
|
+
return mapObject(data, function(value) {
|
|
232
|
+
if (typeof value === "object") {
|
|
233
|
+
value = safeJSONStringify(value);
|
|
234
|
+
}
|
|
235
|
+
return encodeURIComponent(encode(value.toString()));
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function buildQueryString(data) {
|
|
239
|
+
var params = filterObject(data, function(value) {
|
|
240
|
+
return value !== void 0;
|
|
241
|
+
});
|
|
242
|
+
var query = map(
|
|
243
|
+
flatten(encodeParamsObject(params)),
|
|
244
|
+
Util.method("join", "=")
|
|
245
|
+
).join("&");
|
|
246
|
+
return query;
|
|
247
|
+
}
|
|
248
|
+
function decycleObject(object) {
|
|
249
|
+
var objects = [], paths = [];
|
|
250
|
+
return (function derez(value, path) {
|
|
251
|
+
var i, name, nu;
|
|
252
|
+
switch (typeof value) {
|
|
253
|
+
case "object":
|
|
254
|
+
if (!value) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
for (i = 0; i < objects.length; i += 1) {
|
|
258
|
+
if (objects[i] === value) {
|
|
259
|
+
return { $ref: paths[i] };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
objects.push(value);
|
|
263
|
+
paths.push(path);
|
|
264
|
+
if (Object.prototype.toString.apply(value) === "[object Array]") {
|
|
265
|
+
nu = [];
|
|
266
|
+
for (i = 0; i < value.length; i += 1) {
|
|
267
|
+
nu[i] = derez(value[i], path + "[" + i + "]");
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
nu = {};
|
|
271
|
+
for (name in value) {
|
|
272
|
+
if (Object.prototype.hasOwnProperty.call(value, name)) {
|
|
273
|
+
nu[name] = derez(
|
|
274
|
+
value[name],
|
|
275
|
+
path + "[" + JSON.stringify(name) + "]"
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return nu;
|
|
281
|
+
case "number":
|
|
282
|
+
case "string":
|
|
283
|
+
case "boolean":
|
|
284
|
+
return value;
|
|
285
|
+
}
|
|
286
|
+
})(object, "$");
|
|
287
|
+
}
|
|
288
|
+
function safeJSONStringify(source) {
|
|
289
|
+
try {
|
|
290
|
+
return JSON.stringify(source);
|
|
291
|
+
} catch (e) {
|
|
292
|
+
return JSON.stringify(decycleObject(source));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
var Defaults = {
|
|
296
|
+
VERSION: "8.4.0",
|
|
297
|
+
PROTOCOL: 7,
|
|
298
|
+
wsPort: 80,
|
|
299
|
+
wssPort: 443,
|
|
300
|
+
wsPath: "",
|
|
301
|
+
// DEPRECATED: SockJS fallback parameters
|
|
302
|
+
httpHost: "sockjs.pusher.com",
|
|
303
|
+
httpPort: 80,
|
|
304
|
+
httpsPort: 443,
|
|
305
|
+
httpPath: "/pusher",
|
|
306
|
+
// DEPRECATED: Stats
|
|
307
|
+
stats_host: "stats.pusher.com",
|
|
308
|
+
// DEPRECATED: Other settings
|
|
309
|
+
authEndpoint: "/pusher/auth",
|
|
310
|
+
authTransport: "ajax",
|
|
311
|
+
activityTimeout: 12e4,
|
|
312
|
+
pongTimeout: 3e4,
|
|
313
|
+
unavailableTimeout: 1e4,
|
|
314
|
+
userAuthentication: {
|
|
315
|
+
endpoint: "/pusher/user-auth",
|
|
316
|
+
transport: "ajax"
|
|
317
|
+
},
|
|
318
|
+
channelAuthorization: {
|
|
319
|
+
endpoint: "/pusher/auth",
|
|
320
|
+
transport: "ajax"
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
function getGenericURL(baseScheme, params, path) {
|
|
324
|
+
var scheme = baseScheme + (params.useTLS ? "s" : "");
|
|
325
|
+
var host = params.useTLS ? params.hostTLS : params.hostNonTLS;
|
|
326
|
+
return scheme + "://" + host + path;
|
|
327
|
+
}
|
|
328
|
+
function getGenericPath(key, queryString) {
|
|
329
|
+
var path = "/app/" + key;
|
|
330
|
+
var query = "?protocol=" + Defaults.PROTOCOL + "&client=js&version=" + Defaults.VERSION + (queryString ? "&" + queryString : "");
|
|
331
|
+
return path + query;
|
|
332
|
+
}
|
|
333
|
+
var ws = {
|
|
334
|
+
getInitial: function(key, params) {
|
|
335
|
+
var path = (params.httpPath || "") + getGenericPath(key, "flash=false");
|
|
336
|
+
return getGenericURL("ws", params, path);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
var http = {
|
|
340
|
+
getInitial: function(key, params) {
|
|
341
|
+
var path = (params.httpPath || "/pusher") + getGenericPath(key);
|
|
342
|
+
return getGenericURL("http", params, path);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
class CallbackRegistry {
|
|
346
|
+
constructor() {
|
|
347
|
+
this._callbacks = {};
|
|
348
|
+
}
|
|
349
|
+
get(name) {
|
|
350
|
+
return this._callbacks[prefix(name)];
|
|
351
|
+
}
|
|
352
|
+
add(name, callback, context) {
|
|
353
|
+
var prefixedEventName = prefix(name);
|
|
354
|
+
this._callbacks[prefixedEventName] = this._callbacks[prefixedEventName] || [];
|
|
355
|
+
this._callbacks[prefixedEventName].push({
|
|
356
|
+
fn: callback,
|
|
357
|
+
context
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
remove(name, callback, context) {
|
|
361
|
+
if (!name && !callback && !context) {
|
|
362
|
+
this._callbacks = {};
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
var names = name ? [prefix(name)] : keys(this._callbacks);
|
|
366
|
+
if (callback || context) {
|
|
367
|
+
this.removeCallback(names, callback, context);
|
|
368
|
+
} else {
|
|
369
|
+
this.removeAllCallbacks(names);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
removeCallback(names, callback, context) {
|
|
373
|
+
apply(
|
|
374
|
+
names,
|
|
375
|
+
function(name) {
|
|
376
|
+
this._callbacks[name] = filter(
|
|
377
|
+
this._callbacks[name] || [],
|
|
378
|
+
function(binding) {
|
|
379
|
+
return callback && callback !== binding.fn || context && context !== binding.context;
|
|
380
|
+
}
|
|
381
|
+
);
|
|
382
|
+
if (this._callbacks[name].length === 0) {
|
|
383
|
+
delete this._callbacks[name];
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
this
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
removeAllCallbacks(names) {
|
|
390
|
+
apply(
|
|
391
|
+
names,
|
|
392
|
+
function(name) {
|
|
393
|
+
delete this._callbacks[name];
|
|
394
|
+
},
|
|
395
|
+
this
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function prefix(name) {
|
|
400
|
+
return "_" + name;
|
|
401
|
+
}
|
|
402
|
+
class Dispatcher {
|
|
403
|
+
constructor(failThrough) {
|
|
404
|
+
this.callbacks = new CallbackRegistry();
|
|
405
|
+
this.global_callbacks = [];
|
|
406
|
+
this.failThrough = failThrough;
|
|
407
|
+
}
|
|
408
|
+
bind(eventName, callback, context) {
|
|
409
|
+
this.callbacks.add(eventName, callback, context);
|
|
410
|
+
return this;
|
|
411
|
+
}
|
|
412
|
+
bind_global(callback) {
|
|
413
|
+
this.global_callbacks.push(callback);
|
|
414
|
+
return this;
|
|
415
|
+
}
|
|
416
|
+
unbind(eventName, callback, context) {
|
|
417
|
+
this.callbacks.remove(eventName, callback, context);
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
unbind_global(callback) {
|
|
421
|
+
if (!callback) {
|
|
422
|
+
this.global_callbacks = [];
|
|
423
|
+
return this;
|
|
424
|
+
}
|
|
425
|
+
this.global_callbacks = filter(
|
|
426
|
+
this.global_callbacks || [],
|
|
427
|
+
(c) => c !== callback
|
|
428
|
+
);
|
|
429
|
+
return this;
|
|
430
|
+
}
|
|
431
|
+
unbind_all() {
|
|
432
|
+
this.unbind();
|
|
433
|
+
this.unbind_global();
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
emit(eventName, data, metadata) {
|
|
437
|
+
for (var i = 0; i < this.global_callbacks.length; i++) {
|
|
438
|
+
this.global_callbacks[i](eventName, data);
|
|
439
|
+
}
|
|
440
|
+
var callbacks = this.callbacks.get(eventName);
|
|
441
|
+
var args = [];
|
|
442
|
+
if (metadata) {
|
|
443
|
+
args.push(data, metadata);
|
|
444
|
+
} else if (data) {
|
|
445
|
+
args.push(data);
|
|
446
|
+
}
|
|
447
|
+
if (callbacks && callbacks.length > 0) {
|
|
448
|
+
for (var i = 0; i < callbacks.length; i++) {
|
|
449
|
+
callbacks[i].fn.apply(callbacks[i].context || global, args);
|
|
450
|
+
}
|
|
451
|
+
} else if (this.failThrough) {
|
|
452
|
+
this.failThrough(eventName, data);
|
|
453
|
+
}
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
let config = {
|
|
458
|
+
logToConsole: false
|
|
459
|
+
};
|
|
460
|
+
function setLoggerConfig(newConfig) {
|
|
461
|
+
config = { ...config, ...newConfig };
|
|
462
|
+
}
|
|
463
|
+
class Logger {
|
|
464
|
+
constructor() {
|
|
465
|
+
this.globalLog = (message) => {
|
|
466
|
+
if (global.console && global.console.log) {
|
|
467
|
+
global.console.log(message);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
debug(...args) {
|
|
472
|
+
this.log(this.globalLog, args);
|
|
473
|
+
}
|
|
474
|
+
warn(...args) {
|
|
475
|
+
this.log(this.globalLogWarn, args);
|
|
476
|
+
}
|
|
477
|
+
error(...args) {
|
|
478
|
+
this.log(this.globalLogError, args);
|
|
479
|
+
}
|
|
480
|
+
globalLogWarn(message) {
|
|
481
|
+
if (global.console && global.console.warn) {
|
|
482
|
+
global.console.warn(message);
|
|
483
|
+
} else {
|
|
484
|
+
this.globalLog(message);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
globalLogError(message) {
|
|
488
|
+
if (global.console && global.console.error) {
|
|
489
|
+
global.console.error(message);
|
|
490
|
+
} else {
|
|
491
|
+
this.globalLogWarn(message);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
log(defaultLoggingFunction, ...args) {
|
|
495
|
+
var message = stringify.apply(this, arguments);
|
|
496
|
+
if (config.log) {
|
|
497
|
+
config.log(message);
|
|
498
|
+
} else if (config.logToConsole) {
|
|
499
|
+
const log = defaultLoggingFunction.bind(this);
|
|
500
|
+
log(message);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const Logger$1 = new Logger();
|
|
505
|
+
class TransportConnection extends Dispatcher {
|
|
506
|
+
constructor(hooks2, name, priority, key, options) {
|
|
507
|
+
super();
|
|
508
|
+
this.initialize = NodeJS.transportConnectionInitializer;
|
|
509
|
+
this.hooks = hooks2;
|
|
510
|
+
this.name = name;
|
|
511
|
+
this.priority = priority;
|
|
512
|
+
this.key = key;
|
|
513
|
+
this.options = options;
|
|
514
|
+
this.state = "new";
|
|
515
|
+
this.timeline = options.timeline;
|
|
516
|
+
this.activityTimeout = options.activityTimeout;
|
|
517
|
+
this.id = this.timeline.generateUniqueID();
|
|
518
|
+
}
|
|
519
|
+
/** Checks whether the transport handles activity checks by itself.
|
|
520
|
+
*
|
|
521
|
+
* @return {Boolean}
|
|
522
|
+
*/
|
|
523
|
+
handlesActivityChecks() {
|
|
524
|
+
return Boolean(this.hooks.handlesActivityChecks);
|
|
525
|
+
}
|
|
526
|
+
/** Checks whether the transport supports the ping/pong API.
|
|
527
|
+
*
|
|
528
|
+
* @return {Boolean}
|
|
529
|
+
*/
|
|
530
|
+
supportsPing() {
|
|
531
|
+
return Boolean(this.hooks.supportsPing);
|
|
532
|
+
}
|
|
533
|
+
/** Tries to establish a connection.
|
|
534
|
+
*
|
|
535
|
+
* @returns {Boolean} false if transport is in invalid state
|
|
536
|
+
*/
|
|
537
|
+
connect() {
|
|
538
|
+
if (this.socket || this.state !== "initialized") {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
var url = this.hooks.urls.getInitial(this.key, this.options);
|
|
542
|
+
try {
|
|
543
|
+
this.socket = this.hooks.getSocket(url, this.options);
|
|
544
|
+
} catch (e) {
|
|
545
|
+
Util.defer(() => {
|
|
546
|
+
this.onError(e);
|
|
547
|
+
this.changeState("closed");
|
|
548
|
+
});
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
this.bindListeners();
|
|
552
|
+
Logger$1.debug("Connecting", { transport: this.name, url });
|
|
553
|
+
this.changeState("connecting");
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
/** Closes the connection.
|
|
557
|
+
*
|
|
558
|
+
* @return {Boolean} true if there was a connection to close
|
|
559
|
+
*/
|
|
560
|
+
close() {
|
|
561
|
+
if (this.socket) {
|
|
562
|
+
this.socket.close();
|
|
563
|
+
return true;
|
|
564
|
+
} else {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
/** Sends data over the open connection.
|
|
569
|
+
*
|
|
570
|
+
* @param {String} data
|
|
571
|
+
* @return {Boolean} true only when in the "open" state
|
|
572
|
+
*/
|
|
573
|
+
send(data) {
|
|
574
|
+
if (this.state === "open") {
|
|
575
|
+
Util.defer(() => {
|
|
576
|
+
if (this.socket) {
|
|
577
|
+
this.socket.send(data);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
return true;
|
|
581
|
+
} else {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/** Sends a ping if the connection is open and transport supports it. */
|
|
586
|
+
ping() {
|
|
587
|
+
if (this.state === "open" && this.supportsPing()) {
|
|
588
|
+
this.socket.ping();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
onOpen() {
|
|
592
|
+
if (this.hooks.beforeOpen) {
|
|
593
|
+
this.hooks.beforeOpen(
|
|
594
|
+
this.socket,
|
|
595
|
+
this.hooks.urls.getPath(this.key, this.options)
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
this.changeState("open");
|
|
599
|
+
this.socket.onopen = void 0;
|
|
600
|
+
}
|
|
601
|
+
onError(error) {
|
|
602
|
+
this.emit("error", { type: "WebSocketError", error });
|
|
603
|
+
this.timeline.error(this.buildTimelineMessage({ error: error.toString() }));
|
|
604
|
+
}
|
|
605
|
+
onClose(closeEvent) {
|
|
606
|
+
if (closeEvent) {
|
|
607
|
+
this.changeState("closed", {
|
|
608
|
+
code: closeEvent.code,
|
|
609
|
+
reason: closeEvent.reason,
|
|
610
|
+
wasClean: closeEvent.wasClean
|
|
611
|
+
});
|
|
612
|
+
} else {
|
|
613
|
+
this.changeState("closed");
|
|
614
|
+
}
|
|
615
|
+
this.unbindListeners();
|
|
616
|
+
this.socket = void 0;
|
|
617
|
+
}
|
|
618
|
+
onMessage(message) {
|
|
619
|
+
this.emit("message", message);
|
|
620
|
+
}
|
|
621
|
+
onActivity() {
|
|
622
|
+
this.emit("activity");
|
|
623
|
+
}
|
|
624
|
+
bindListeners() {
|
|
625
|
+
this.socket.onopen = () => {
|
|
626
|
+
this.onOpen();
|
|
627
|
+
};
|
|
628
|
+
this.socket.onerror = (error) => {
|
|
629
|
+
this.onError(error);
|
|
630
|
+
};
|
|
631
|
+
this.socket.onclose = (closeEvent) => {
|
|
632
|
+
this.onClose(closeEvent);
|
|
633
|
+
};
|
|
634
|
+
this.socket.onmessage = (message) => {
|
|
635
|
+
this.onMessage(message);
|
|
636
|
+
};
|
|
637
|
+
if (this.supportsPing()) {
|
|
638
|
+
this.socket.onactivity = () => {
|
|
639
|
+
this.onActivity();
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
unbindListeners() {
|
|
644
|
+
if (this.socket) {
|
|
645
|
+
this.socket.onopen = void 0;
|
|
646
|
+
this.socket.onerror = void 0;
|
|
647
|
+
this.socket.onclose = void 0;
|
|
648
|
+
this.socket.onmessage = void 0;
|
|
649
|
+
if (this.supportsPing()) {
|
|
650
|
+
this.socket.onactivity = void 0;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
changeState(state, params) {
|
|
655
|
+
this.state = state;
|
|
656
|
+
this.timeline.info(
|
|
657
|
+
this.buildTimelineMessage({
|
|
658
|
+
state,
|
|
659
|
+
params
|
|
660
|
+
})
|
|
661
|
+
);
|
|
662
|
+
this.emit(state, params);
|
|
663
|
+
}
|
|
664
|
+
buildTimelineMessage(message) {
|
|
665
|
+
return extend({ cid: this.id }, message);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
class Transport {
|
|
669
|
+
constructor(hooks2) {
|
|
670
|
+
this.hooks = hooks2;
|
|
671
|
+
}
|
|
672
|
+
/** Returns whether the transport is supported in the environment.
|
|
673
|
+
*
|
|
674
|
+
* @param {Object} envronment te environment details (encryption, settings)
|
|
675
|
+
* @returns {Boolean} true when the transport is supported
|
|
676
|
+
*/
|
|
677
|
+
isSupported(environment) {
|
|
678
|
+
return this.hooks.isSupported(environment);
|
|
679
|
+
}
|
|
680
|
+
/** Creates a transport connection.
|
|
681
|
+
*
|
|
682
|
+
* @param {String} name
|
|
683
|
+
* @param {Number} priority
|
|
684
|
+
* @param {String} key the application key
|
|
685
|
+
* @param {Object} options
|
|
686
|
+
* @returns {TransportConnection}
|
|
687
|
+
*/
|
|
688
|
+
createConnection(name, priority, key, options) {
|
|
689
|
+
return new TransportConnection(this.hooks, name, priority, key, options);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
var WSTransport = new Transport({
|
|
693
|
+
urls: ws,
|
|
694
|
+
handlesActivityChecks: false,
|
|
695
|
+
supportsPing: false,
|
|
696
|
+
isInitialized: function() {
|
|
697
|
+
return Boolean(NodeJS.getWebSocketAPI());
|
|
698
|
+
},
|
|
699
|
+
isSupported: function() {
|
|
700
|
+
return Boolean(NodeJS.getWebSocketAPI());
|
|
701
|
+
},
|
|
702
|
+
getSocket: function(url) {
|
|
703
|
+
return NodeJS.createWebSocket(url);
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
var httpConfiguration = {
|
|
707
|
+
urls: http,
|
|
708
|
+
handlesActivityChecks: false,
|
|
709
|
+
supportsPing: true,
|
|
710
|
+
isInitialized: function() {
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
var streamingConfiguration = extend(
|
|
715
|
+
{
|
|
716
|
+
getSocket: function(url) {
|
|
717
|
+
return NodeJS.HTTPFactory.createStreamingSocket(url);
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
httpConfiguration
|
|
721
|
+
);
|
|
722
|
+
var pollingConfiguration = extend(
|
|
723
|
+
{
|
|
724
|
+
getSocket: function(url) {
|
|
725
|
+
return NodeJS.HTTPFactory.createPollingSocket(url);
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
httpConfiguration
|
|
729
|
+
);
|
|
730
|
+
var xhrConfiguration = {
|
|
731
|
+
isSupported: function() {
|
|
732
|
+
return NodeJS.isXHRSupported();
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
var XHRStreamingTransport = new Transport(
|
|
736
|
+
extend({}, streamingConfiguration, xhrConfiguration)
|
|
737
|
+
);
|
|
738
|
+
var XHRPollingTransport = new Transport(
|
|
739
|
+
extend({}, pollingConfiguration, xhrConfiguration)
|
|
740
|
+
);
|
|
741
|
+
var Transports$2 = {
|
|
742
|
+
ws: WSTransport,
|
|
743
|
+
xhr_streaming: XHRStreamingTransport,
|
|
744
|
+
xhr_polling: XHRPollingTransport
|
|
745
|
+
};
|
|
746
|
+
class AssistantToTheTransportManager {
|
|
747
|
+
constructor(manager, transport, options) {
|
|
748
|
+
this.manager = manager;
|
|
749
|
+
this.transport = transport;
|
|
750
|
+
this.minPingDelay = options.minPingDelay;
|
|
751
|
+
this.maxPingDelay = options.maxPingDelay;
|
|
752
|
+
this.pingDelay = void 0;
|
|
753
|
+
}
|
|
754
|
+
/** Creates a transport connection.
|
|
755
|
+
*
|
|
756
|
+
* This function has the same API as Transport#createConnection.
|
|
757
|
+
*
|
|
758
|
+
* @param {String} name
|
|
759
|
+
* @param {Number} priority
|
|
760
|
+
* @param {String} key the application key
|
|
761
|
+
* @param {Object} options
|
|
762
|
+
* @returns {TransportConnection}
|
|
763
|
+
*/
|
|
764
|
+
createConnection(name, priority, key, options) {
|
|
765
|
+
options = extend({}, options, {
|
|
766
|
+
activityTimeout: this.pingDelay
|
|
767
|
+
});
|
|
768
|
+
var connection = this.transport.createConnection(
|
|
769
|
+
name,
|
|
770
|
+
priority,
|
|
771
|
+
key,
|
|
772
|
+
options
|
|
773
|
+
);
|
|
774
|
+
var openTimestamp = null;
|
|
775
|
+
var onOpen = function() {
|
|
776
|
+
connection.unbind("open", onOpen);
|
|
777
|
+
connection.bind("closed", onClosed);
|
|
778
|
+
openTimestamp = Util.now();
|
|
779
|
+
};
|
|
780
|
+
var onClosed = (closeEvent) => {
|
|
781
|
+
connection.unbind("closed", onClosed);
|
|
782
|
+
if (closeEvent.code === 1002 || closeEvent.code === 1003) {
|
|
783
|
+
this.manager.reportDeath();
|
|
784
|
+
} else if (!closeEvent.wasClean && openTimestamp) {
|
|
785
|
+
var lifespan = Util.now() - openTimestamp;
|
|
786
|
+
if (lifespan < 2 * this.maxPingDelay) {
|
|
787
|
+
this.manager.reportDeath();
|
|
788
|
+
this.pingDelay = Math.max(lifespan / 2, this.minPingDelay);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
connection.bind("open", onOpen);
|
|
793
|
+
return connection;
|
|
794
|
+
}
|
|
795
|
+
/** Returns whether the transport is supported in the environment.
|
|
796
|
+
*
|
|
797
|
+
* This function has the same API as Transport#isSupported. Might return false
|
|
798
|
+
* when the manager decides to kill the transport.
|
|
799
|
+
*
|
|
800
|
+
* @param {Object} environment the environment details (encryption, settings)
|
|
801
|
+
* @returns {Boolean} true when the transport is supported
|
|
802
|
+
*/
|
|
803
|
+
isSupported(environment) {
|
|
804
|
+
return this.manager.isAlive() && this.transport.isSupported(environment);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
const Protocol = {
|
|
808
|
+
/**
|
|
809
|
+
* Decodes a message in a Pusher format.
|
|
810
|
+
*
|
|
811
|
+
* The MessageEvent we receive from the transport should contain a pusher event
|
|
812
|
+
* (https://pusher.com/docs/pusher_protocol#events) serialized as JSON in the
|
|
813
|
+
* data field
|
|
814
|
+
*
|
|
815
|
+
* The pusher event may contain a data field too, and it may also be
|
|
816
|
+
* serialised as JSON
|
|
817
|
+
*
|
|
818
|
+
* Throws errors when messages are not parse'able.
|
|
819
|
+
*
|
|
820
|
+
* @param {MessageEvent} messageEvent
|
|
821
|
+
* @return {PusherEvent}
|
|
822
|
+
*/
|
|
823
|
+
decodeMessage: function(messageEvent) {
|
|
824
|
+
try {
|
|
825
|
+
var messageData = JSON.parse(messageEvent.data);
|
|
826
|
+
var pusherEventData = messageData.data;
|
|
827
|
+
if (typeof pusherEventData === "string") {
|
|
828
|
+
try {
|
|
829
|
+
pusherEventData = JSON.parse(messageData.data);
|
|
830
|
+
} catch (e) {
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
var pusherEvent = {
|
|
834
|
+
event: messageData.event,
|
|
835
|
+
channel: messageData.channel,
|
|
836
|
+
data: pusherEventData,
|
|
837
|
+
rawMessage: messageEvent.data
|
|
838
|
+
// Preserve raw message for delta compression
|
|
839
|
+
};
|
|
840
|
+
if (messageData.user_id) {
|
|
841
|
+
pusherEvent.user_id = messageData.user_id;
|
|
842
|
+
}
|
|
843
|
+
const sequence = messageData.__delta_seq ?? messageData.sequence;
|
|
844
|
+
const conflationKey = messageData.__conflation_key ?? messageData.conflation_key;
|
|
845
|
+
if (typeof sequence === "number") {
|
|
846
|
+
pusherEvent.sequence = sequence;
|
|
847
|
+
}
|
|
848
|
+
if (conflationKey !== void 0) {
|
|
849
|
+
pusherEvent.conflation_key = conflationKey;
|
|
850
|
+
}
|
|
851
|
+
return pusherEvent;
|
|
852
|
+
} catch (e) {
|
|
853
|
+
throw { type: "MessageParseError", error: e, data: messageEvent.data };
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
/**
|
|
857
|
+
* Encodes a message to be sent.
|
|
858
|
+
*
|
|
859
|
+
* @param {PusherEvent} event
|
|
860
|
+
* @return {String}
|
|
861
|
+
*/
|
|
862
|
+
encodeMessage: function(event) {
|
|
863
|
+
return JSON.stringify(event);
|
|
864
|
+
},
|
|
865
|
+
/**
|
|
866
|
+
* Processes a handshake message and returns appropriate actions.
|
|
867
|
+
*
|
|
868
|
+
* Returns an object with an 'action' and other action-specific properties.
|
|
869
|
+
*
|
|
870
|
+
* There are three outcomes when calling this function. First is a successful
|
|
871
|
+
* connection attempt, when pusher:connection_established is received, which
|
|
872
|
+
* results in a 'connected' action with an 'id' property. When passed a
|
|
873
|
+
* pusher:error event, it returns a result with action appropriate to the
|
|
874
|
+
* close code and an error. Otherwise, it raises an exception.
|
|
875
|
+
*
|
|
876
|
+
* @param {String} message
|
|
877
|
+
* @result Object
|
|
878
|
+
*/
|
|
879
|
+
processHandshake: function(messageEvent) {
|
|
880
|
+
var message = Protocol.decodeMessage(messageEvent);
|
|
881
|
+
if (message.event === "pusher:connection_established") {
|
|
882
|
+
if (!message.data.activity_timeout) {
|
|
883
|
+
throw "No activity timeout specified in handshake";
|
|
884
|
+
}
|
|
885
|
+
return {
|
|
886
|
+
action: "connected",
|
|
887
|
+
id: message.data.socket_id,
|
|
888
|
+
activityTimeout: message.data.activity_timeout * 1e3
|
|
889
|
+
};
|
|
890
|
+
} else if (message.event === "pusher:error") {
|
|
891
|
+
return {
|
|
892
|
+
action: this.getCloseAction(message.data),
|
|
893
|
+
error: this.getCloseError(message.data)
|
|
894
|
+
};
|
|
895
|
+
} else {
|
|
896
|
+
throw "Invalid handshake";
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
/**
|
|
900
|
+
* Dispatches the close event and returns an appropriate action name.
|
|
901
|
+
*
|
|
902
|
+
* See:
|
|
903
|
+
* 1. https://developer.mozilla.org/en-US/docs/WebSockets/WebSockets_reference/CloseEvent
|
|
904
|
+
* 2. http://pusher.com/docs/pusher_protocol
|
|
905
|
+
*
|
|
906
|
+
* @param {CloseEvent} closeEvent
|
|
907
|
+
* @return {String} close action name
|
|
908
|
+
*/
|
|
909
|
+
getCloseAction: function(closeEvent) {
|
|
910
|
+
if (closeEvent.code < 4e3) {
|
|
911
|
+
if (closeEvent.code >= 1002 && closeEvent.code <= 1004) {
|
|
912
|
+
return "backoff";
|
|
913
|
+
} else {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
} else if (closeEvent.code === 4e3) {
|
|
917
|
+
return "tls_only";
|
|
918
|
+
} else if (closeEvent.code < 4100) {
|
|
919
|
+
return "refused";
|
|
920
|
+
} else if (closeEvent.code < 4200) {
|
|
921
|
+
return "backoff";
|
|
922
|
+
} else if (closeEvent.code < 4300) {
|
|
923
|
+
return "retry";
|
|
924
|
+
} else {
|
|
925
|
+
return "refused";
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
/**
|
|
929
|
+
* Returns an error or null basing on the close event.
|
|
930
|
+
*
|
|
931
|
+
* Null is returned when connection was closed cleanly. Otherwise, an object
|
|
932
|
+
* with error details is returned.
|
|
933
|
+
*
|
|
934
|
+
* @param {CloseEvent} closeEvent
|
|
935
|
+
* @return {Object} error object
|
|
936
|
+
*/
|
|
937
|
+
getCloseError: function(closeEvent) {
|
|
938
|
+
if (closeEvent.code !== 1e3 && closeEvent.code !== 1001) {
|
|
939
|
+
return {
|
|
940
|
+
type: "PusherError",
|
|
941
|
+
data: {
|
|
942
|
+
code: closeEvent.code,
|
|
943
|
+
message: closeEvent.reason || closeEvent.message
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
} else {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
class Connection extends Dispatcher {
|
|
952
|
+
constructor(id, transport) {
|
|
953
|
+
super();
|
|
954
|
+
this.id = id;
|
|
955
|
+
this.transport = transport;
|
|
956
|
+
this.activityTimeout = transport.activityTimeout;
|
|
957
|
+
this.bindListeners();
|
|
958
|
+
}
|
|
959
|
+
/** Returns whether used transport handles activity checks by itself
|
|
960
|
+
*
|
|
961
|
+
* @returns {Boolean} true if activity checks are handled by the transport
|
|
962
|
+
*/
|
|
963
|
+
handlesActivityChecks() {
|
|
964
|
+
return this.transport.handlesActivityChecks();
|
|
965
|
+
}
|
|
966
|
+
/** Sends raw data.
|
|
967
|
+
*
|
|
968
|
+
* @param {String} data
|
|
969
|
+
*/
|
|
970
|
+
send(data) {
|
|
971
|
+
return this.transport.send(data);
|
|
972
|
+
}
|
|
973
|
+
/** Sends an event.
|
|
974
|
+
*
|
|
975
|
+
* @param {String} name
|
|
976
|
+
* @param {String} data
|
|
977
|
+
* @param {String} [channel]
|
|
978
|
+
* @returns {Boolean} whether message was sent or not
|
|
979
|
+
*/
|
|
980
|
+
send_event(name, data, channel) {
|
|
981
|
+
var event = { event: name, data };
|
|
982
|
+
if (channel) {
|
|
983
|
+
event.channel = channel;
|
|
984
|
+
}
|
|
985
|
+
Logger$1.debug("Event sent", event);
|
|
986
|
+
return this.send(Protocol.encodeMessage(event));
|
|
987
|
+
}
|
|
988
|
+
/** Sends a ping message to the server.
|
|
989
|
+
*
|
|
990
|
+
* Basing on the underlying transport, it might send either transport's
|
|
991
|
+
* protocol-specific ping or pusher:ping event.
|
|
992
|
+
*/
|
|
993
|
+
ping() {
|
|
994
|
+
if (this.transport.supportsPing()) {
|
|
995
|
+
this.transport.ping();
|
|
996
|
+
} else {
|
|
997
|
+
this.send_event("pusher:ping", {});
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
/** Closes the connection. */
|
|
1001
|
+
close() {
|
|
1002
|
+
this.transport.close();
|
|
1003
|
+
}
|
|
1004
|
+
bindListeners() {
|
|
1005
|
+
var listeners = {
|
|
1006
|
+
message: (messageEvent) => {
|
|
1007
|
+
var pusherEvent;
|
|
1008
|
+
try {
|
|
1009
|
+
pusherEvent = Protocol.decodeMessage(messageEvent);
|
|
1010
|
+
} catch (e) {
|
|
1011
|
+
this.emit("error", {
|
|
1012
|
+
type: "MessageParseError",
|
|
1013
|
+
error: e,
|
|
1014
|
+
data: messageEvent.data
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
if (pusherEvent !== void 0) {
|
|
1018
|
+
Logger$1.debug("Event recd", pusherEvent);
|
|
1019
|
+
switch (pusherEvent.event) {
|
|
1020
|
+
case "pusher:error":
|
|
1021
|
+
this.emit("error", {
|
|
1022
|
+
type: "PusherError",
|
|
1023
|
+
data: pusherEvent.data
|
|
1024
|
+
});
|
|
1025
|
+
break;
|
|
1026
|
+
case "pusher:ping":
|
|
1027
|
+
this.emit("ping");
|
|
1028
|
+
break;
|
|
1029
|
+
case "pusher:pong":
|
|
1030
|
+
this.emit("pong");
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
this.emit("message", pusherEvent);
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
activity: () => {
|
|
1037
|
+
this.emit("activity");
|
|
1038
|
+
},
|
|
1039
|
+
error: (error) => {
|
|
1040
|
+
this.emit("error", error);
|
|
1041
|
+
},
|
|
1042
|
+
closed: (closeEvent) => {
|
|
1043
|
+
unbindListeners();
|
|
1044
|
+
if (closeEvent && closeEvent.code) {
|
|
1045
|
+
this.handleCloseEvent(closeEvent);
|
|
1046
|
+
}
|
|
1047
|
+
this.transport = null;
|
|
1048
|
+
this.emit("closed");
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
var unbindListeners = () => {
|
|
1052
|
+
objectApply(listeners, (listener, event) => {
|
|
1053
|
+
this.transport.unbind(event, listener);
|
|
1054
|
+
});
|
|
1055
|
+
};
|
|
1056
|
+
objectApply(listeners, (listener, event) => {
|
|
1057
|
+
this.transport.bind(event, listener);
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
handleCloseEvent(closeEvent) {
|
|
1061
|
+
var action = Protocol.getCloseAction(closeEvent);
|
|
1062
|
+
var error = Protocol.getCloseError(closeEvent);
|
|
1063
|
+
if (error) {
|
|
1064
|
+
this.emit("error", error);
|
|
1065
|
+
}
|
|
1066
|
+
if (action) {
|
|
1067
|
+
this.emit(action, { action, error });
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
class Handshake {
|
|
1072
|
+
constructor(transport, callback) {
|
|
1073
|
+
this.transport = transport;
|
|
1074
|
+
this.callback = callback;
|
|
1075
|
+
this.bindListeners();
|
|
1076
|
+
}
|
|
1077
|
+
close() {
|
|
1078
|
+
this.unbindListeners();
|
|
1079
|
+
this.transport.close();
|
|
1080
|
+
}
|
|
1081
|
+
bindListeners() {
|
|
1082
|
+
this.onMessage = (m) => {
|
|
1083
|
+
this.unbindListeners();
|
|
1084
|
+
var result;
|
|
1085
|
+
try {
|
|
1086
|
+
result = Protocol.processHandshake(m);
|
|
1087
|
+
} catch (e) {
|
|
1088
|
+
this.finish("error", { error: e });
|
|
1089
|
+
this.transport.close();
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
if (result.action === "connected") {
|
|
1093
|
+
this.finish("connected", {
|
|
1094
|
+
connection: new Connection(result.id, this.transport),
|
|
1095
|
+
activityTimeout: result.activityTimeout
|
|
1096
|
+
});
|
|
1097
|
+
} else {
|
|
1098
|
+
this.finish(result.action, { error: result.error });
|
|
1099
|
+
this.transport.close();
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
this.onClosed = (closeEvent) => {
|
|
1103
|
+
this.unbindListeners();
|
|
1104
|
+
var action = Protocol.getCloseAction(closeEvent) || "backoff";
|
|
1105
|
+
var error = Protocol.getCloseError(closeEvent);
|
|
1106
|
+
this.finish(action, { error });
|
|
1107
|
+
};
|
|
1108
|
+
this.transport.bind("message", this.onMessage);
|
|
1109
|
+
this.transport.bind("closed", this.onClosed);
|
|
1110
|
+
}
|
|
1111
|
+
unbindListeners() {
|
|
1112
|
+
this.transport.unbind("message", this.onMessage);
|
|
1113
|
+
this.transport.unbind("closed", this.onClosed);
|
|
1114
|
+
}
|
|
1115
|
+
finish(action, params) {
|
|
1116
|
+
this.callback(
|
|
1117
|
+
extend({ transport: this.transport, action }, params)
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
class TimelineSender {
|
|
1122
|
+
constructor(timeline, options) {
|
|
1123
|
+
this.timeline = timeline;
|
|
1124
|
+
this.options = options || {};
|
|
1125
|
+
}
|
|
1126
|
+
send(useTLS, callback) {
|
|
1127
|
+
if (this.timeline.isEmpty()) {
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
this.timeline.send(
|
|
1131
|
+
NodeJS.TimelineTransport.getAgent(this, useTLS),
|
|
1132
|
+
callback
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
class BadEventName extends Error {
|
|
1137
|
+
constructor(msg) {
|
|
1138
|
+
super(msg);
|
|
1139
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
class BadChannelName extends Error {
|
|
1143
|
+
constructor(msg) {
|
|
1144
|
+
super(msg);
|
|
1145
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
class TransportPriorityTooLow extends Error {
|
|
1149
|
+
constructor(msg) {
|
|
1150
|
+
super(msg);
|
|
1151
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
class TransportClosed extends Error {
|
|
1155
|
+
constructor(msg) {
|
|
1156
|
+
super(msg);
|
|
1157
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
class UnsupportedFeature extends Error {
|
|
1161
|
+
constructor(msg) {
|
|
1162
|
+
super(msg);
|
|
1163
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
class UnsupportedTransport extends Error {
|
|
1167
|
+
constructor(msg) {
|
|
1168
|
+
super(msg);
|
|
1169
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
let UnsupportedStrategy$1 = class UnsupportedStrategy extends Error {
|
|
1173
|
+
constructor(msg) {
|
|
1174
|
+
super(msg);
|
|
1175
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
class HTTPAuthError extends Error {
|
|
1179
|
+
constructor(status, msg) {
|
|
1180
|
+
super(msg);
|
|
1181
|
+
this.status = status;
|
|
1182
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
const urlStore = {
|
|
1186
|
+
baseUrl: "https://pusher.com",
|
|
1187
|
+
urls: {
|
|
1188
|
+
authenticationEndpoint: {
|
|
1189
|
+
path: "/docs/channels/server_api/authenticating_users"
|
|
1190
|
+
},
|
|
1191
|
+
authorizationEndpoint: {
|
|
1192
|
+
path: "/docs/channels/server_api/authorizing-users/"
|
|
1193
|
+
},
|
|
1194
|
+
javascriptQuickStart: {
|
|
1195
|
+
path: "/docs/javascript_quick_start"
|
|
1196
|
+
},
|
|
1197
|
+
triggeringClientEvents: {
|
|
1198
|
+
path: "/docs/client_api_guide/client_events#trigger-events"
|
|
1199
|
+
},
|
|
1200
|
+
encryptedChannelSupport: {
|
|
1201
|
+
fullUrl: "https://github.com/pusher/pusher-js/tree/cc491015371a4bde5743d1c87a0fbac0feb53195#encrypted-channel-support"
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
const buildLogSuffix = function(key) {
|
|
1206
|
+
const urlPrefix = "See:";
|
|
1207
|
+
const urlObj = urlStore.urls[key];
|
|
1208
|
+
if (!urlObj) return "";
|
|
1209
|
+
let url;
|
|
1210
|
+
if (urlObj.fullUrl) {
|
|
1211
|
+
url = urlObj.fullUrl;
|
|
1212
|
+
} else if (urlObj.path) {
|
|
1213
|
+
url = urlStore.baseUrl + urlObj.path;
|
|
1214
|
+
}
|
|
1215
|
+
if (!url) return "";
|
|
1216
|
+
return `${urlPrefix} ${url}`;
|
|
1217
|
+
};
|
|
1218
|
+
const UrlStore = { buildLogSuffix };
|
|
1219
|
+
class Channel extends Dispatcher {
|
|
1220
|
+
constructor(name, pusher) {
|
|
1221
|
+
super(function(event, data) {
|
|
1222
|
+
Logger$1.debug("No callbacks on " + name + " for " + event);
|
|
1223
|
+
});
|
|
1224
|
+
this.name = name;
|
|
1225
|
+
this.pusher = pusher;
|
|
1226
|
+
this.subscribed = false;
|
|
1227
|
+
this.subscriptionPending = false;
|
|
1228
|
+
this.subscriptionCancelled = false;
|
|
1229
|
+
this.tagsFilter = null;
|
|
1230
|
+
}
|
|
1231
|
+
/** Skips authorization, since public channels don't require it.
|
|
1232
|
+
*
|
|
1233
|
+
* @param {Function} callback
|
|
1234
|
+
*/
|
|
1235
|
+
authorize(socketId, callback) {
|
|
1236
|
+
return callback(null, { auth: "" });
|
|
1237
|
+
}
|
|
1238
|
+
/** Triggers an event */
|
|
1239
|
+
trigger(event, data) {
|
|
1240
|
+
if (event.indexOf("client-") !== 0) {
|
|
1241
|
+
throw new BadEventName(
|
|
1242
|
+
"Event '" + event + "' does not start with 'client-'"
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1245
|
+
if (!this.subscribed) {
|
|
1246
|
+
var suffix = UrlStore.buildLogSuffix("triggeringClientEvents");
|
|
1247
|
+
Logger$1.warn(
|
|
1248
|
+
`Client event triggered before channel 'subscription_succeeded' event . ${suffix}`
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
return this.pusher.send_event(event, data, this.name);
|
|
1252
|
+
}
|
|
1253
|
+
/** Signals disconnection to the channel. For internal use only. */
|
|
1254
|
+
disconnect() {
|
|
1255
|
+
this.subscribed = false;
|
|
1256
|
+
this.subscriptionPending = false;
|
|
1257
|
+
}
|
|
1258
|
+
/** Handles a PusherEvent. For internal use only.
|
|
1259
|
+
*
|
|
1260
|
+
* @param {PusherEvent} event
|
|
1261
|
+
*/
|
|
1262
|
+
handleEvent(event) {
|
|
1263
|
+
var eventName = event.event;
|
|
1264
|
+
var data = event.data;
|
|
1265
|
+
if (eventName === "pusher_internal:subscription_succeeded") {
|
|
1266
|
+
this.handleSubscriptionSucceededEvent(event);
|
|
1267
|
+
} else if (eventName === "pusher_internal:subscription_count") {
|
|
1268
|
+
this.handleSubscriptionCountEvent(event);
|
|
1269
|
+
} else if (eventName.indexOf("pusher_internal:") !== 0) {
|
|
1270
|
+
var metadata = {};
|
|
1271
|
+
this.emit(eventName, data, metadata);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
handleSubscriptionSucceededEvent(event) {
|
|
1275
|
+
this.subscriptionPending = false;
|
|
1276
|
+
this.subscribed = true;
|
|
1277
|
+
if (this.subscriptionCancelled) {
|
|
1278
|
+
this.pusher.unsubscribe(this.name);
|
|
1279
|
+
} else {
|
|
1280
|
+
this.emit("pusher:subscription_succeeded", event.data);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
handleSubscriptionCountEvent(event) {
|
|
1284
|
+
if (event.data.subscription_count) {
|
|
1285
|
+
this.subscriptionCount = event.data.subscription_count;
|
|
1286
|
+
}
|
|
1287
|
+
this.emit("pusher:subscription_count", event.data);
|
|
1288
|
+
}
|
|
1289
|
+
/** Sends a subscription request. For internal use only. */
|
|
1290
|
+
subscribe() {
|
|
1291
|
+
if (this.subscribed) {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
this.subscriptionPending = true;
|
|
1295
|
+
this.subscriptionCancelled = false;
|
|
1296
|
+
this.authorize(
|
|
1297
|
+
this.pusher.connection.socket_id,
|
|
1298
|
+
(error, data) => {
|
|
1299
|
+
if (error) {
|
|
1300
|
+
this.subscriptionPending = false;
|
|
1301
|
+
Logger$1.error(error.toString());
|
|
1302
|
+
this.emit(
|
|
1303
|
+
"pusher:subscription_error",
|
|
1304
|
+
Object.assign(
|
|
1305
|
+
{},
|
|
1306
|
+
{
|
|
1307
|
+
type: "AuthError",
|
|
1308
|
+
error: error.message
|
|
1309
|
+
},
|
|
1310
|
+
error instanceof HTTPAuthError ? { status: error.status } : {}
|
|
1311
|
+
)
|
|
1312
|
+
);
|
|
1313
|
+
} else {
|
|
1314
|
+
const subscribeData = {
|
|
1315
|
+
auth: data.auth,
|
|
1316
|
+
channel_data: data.channel_data,
|
|
1317
|
+
channel: this.name
|
|
1318
|
+
};
|
|
1319
|
+
if (this.tagsFilter) {
|
|
1320
|
+
subscribeData.tags_filter = this.tagsFilter;
|
|
1321
|
+
}
|
|
1322
|
+
this.pusher.send_event("pusher:subscribe", subscribeData);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
);
|
|
1326
|
+
}
|
|
1327
|
+
/** Sends an unsubscription request. For internal use only. */
|
|
1328
|
+
unsubscribe() {
|
|
1329
|
+
this.subscribed = false;
|
|
1330
|
+
this.pusher.send_event("pusher:unsubscribe", {
|
|
1331
|
+
channel: this.name
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
/** Cancels an in progress subscription. For internal use only. */
|
|
1335
|
+
cancelSubscription() {
|
|
1336
|
+
this.subscriptionCancelled = true;
|
|
1337
|
+
}
|
|
1338
|
+
/** Reinstates an in progress subscripiton. For internal use only. */
|
|
1339
|
+
reinstateSubscription() {
|
|
1340
|
+
this.subscriptionCancelled = false;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
class PrivateChannel extends Channel {
|
|
1344
|
+
/** Authorizes the connection to use the channel.
|
|
1345
|
+
*
|
|
1346
|
+
* @param {String} socketId
|
|
1347
|
+
* @param {Function} callback
|
|
1348
|
+
*/
|
|
1349
|
+
authorize(socketId, callback) {
|
|
1350
|
+
return this.pusher.config.channelAuthorizer(
|
|
1351
|
+
{
|
|
1352
|
+
channelName: this.name,
|
|
1353
|
+
socketId
|
|
1354
|
+
},
|
|
1355
|
+
callback
|
|
1356
|
+
);
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
class Members {
|
|
1360
|
+
constructor() {
|
|
1361
|
+
this.reset();
|
|
1362
|
+
}
|
|
1363
|
+
/** Returns member's info for given id.
|
|
1364
|
+
*
|
|
1365
|
+
* Resulting object containts two fields - id and info.
|
|
1366
|
+
*
|
|
1367
|
+
* @param {Number} id
|
|
1368
|
+
* @return {Object} member's info or null
|
|
1369
|
+
*/
|
|
1370
|
+
get(id) {
|
|
1371
|
+
if (Object.prototype.hasOwnProperty.call(this.members, id)) {
|
|
1372
|
+
return {
|
|
1373
|
+
id,
|
|
1374
|
+
info: this.members[id]
|
|
1375
|
+
};
|
|
1376
|
+
} else {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
/** Calls back for each member in unspecified order.
|
|
1381
|
+
*
|
|
1382
|
+
* @param {Function} callback
|
|
1383
|
+
*/
|
|
1384
|
+
each(callback) {
|
|
1385
|
+
objectApply(this.members, (member, id) => {
|
|
1386
|
+
callback(this.get(id));
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
/** Updates the id for connected member. For internal use only. */
|
|
1390
|
+
setMyID(id) {
|
|
1391
|
+
this.myID = id;
|
|
1392
|
+
}
|
|
1393
|
+
/** Handles subscription data. For internal use only. */
|
|
1394
|
+
onSubscription(subscriptionData) {
|
|
1395
|
+
this.members = subscriptionData.presence.hash;
|
|
1396
|
+
this.count = subscriptionData.presence.count;
|
|
1397
|
+
this.me = this.get(this.myID);
|
|
1398
|
+
}
|
|
1399
|
+
/** Adds a new member to the collection. For internal use only. */
|
|
1400
|
+
addMember(memberData) {
|
|
1401
|
+
if (this.get(memberData.user_id) === null) {
|
|
1402
|
+
this.count++;
|
|
1403
|
+
}
|
|
1404
|
+
this.members[memberData.user_id] = memberData.user_info;
|
|
1405
|
+
return this.get(memberData.user_id);
|
|
1406
|
+
}
|
|
1407
|
+
/** Adds a member from the collection. For internal use only. */
|
|
1408
|
+
removeMember(memberData) {
|
|
1409
|
+
var member = this.get(memberData.user_id);
|
|
1410
|
+
if (member) {
|
|
1411
|
+
delete this.members[memberData.user_id];
|
|
1412
|
+
this.count--;
|
|
1413
|
+
}
|
|
1414
|
+
return member;
|
|
1415
|
+
}
|
|
1416
|
+
/** Resets the collection to the initial state. For internal use only. */
|
|
1417
|
+
reset() {
|
|
1418
|
+
this.members = {};
|
|
1419
|
+
this.count = 0;
|
|
1420
|
+
this.myID = null;
|
|
1421
|
+
this.me = null;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
class PresenceChannel extends PrivateChannel {
|
|
1425
|
+
/** Adds presence channel functionality to private channels.
|
|
1426
|
+
*
|
|
1427
|
+
* @param {String} name
|
|
1428
|
+
* @param {Pusher} pusher
|
|
1429
|
+
*/
|
|
1430
|
+
constructor(name, pusher) {
|
|
1431
|
+
super(name, pusher);
|
|
1432
|
+
this.members = new Members();
|
|
1433
|
+
}
|
|
1434
|
+
/** Authorizes the connection as a member of the channel.
|
|
1435
|
+
*
|
|
1436
|
+
* @param {String} socketId
|
|
1437
|
+
* @param {Function} callback
|
|
1438
|
+
*/
|
|
1439
|
+
authorize(socketId, callback) {
|
|
1440
|
+
super.authorize(socketId, async (error, authData) => {
|
|
1441
|
+
if (!error) {
|
|
1442
|
+
authData = authData;
|
|
1443
|
+
if (authData.channel_data != null) {
|
|
1444
|
+
var channelData = JSON.parse(authData.channel_data);
|
|
1445
|
+
this.members.setMyID(channelData.user_id);
|
|
1446
|
+
} else {
|
|
1447
|
+
await this.pusher.user.signinDonePromise;
|
|
1448
|
+
if (this.pusher.user.user_data != null) {
|
|
1449
|
+
this.members.setMyID(this.pusher.user.user_data.id);
|
|
1450
|
+
} else {
|
|
1451
|
+
let suffix = UrlStore.buildLogSuffix("authorizationEndpoint");
|
|
1452
|
+
Logger$1.error(
|
|
1453
|
+
`Invalid auth response for channel '${this.name}', expected 'channel_data' field. ${suffix}, or the user should be signed in.`
|
|
1454
|
+
);
|
|
1455
|
+
callback("Invalid auth response");
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
callback(error, authData);
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
/** Handles presence and subscription events. For internal use only.
|
|
1464
|
+
*
|
|
1465
|
+
* @param {PusherEvent} event
|
|
1466
|
+
*/
|
|
1467
|
+
handleEvent(event) {
|
|
1468
|
+
var eventName = event.event;
|
|
1469
|
+
if (eventName.indexOf("pusher_internal:") === 0) {
|
|
1470
|
+
this.handleInternalEvent(event);
|
|
1471
|
+
} else {
|
|
1472
|
+
var data = event.data;
|
|
1473
|
+
var metadata = {};
|
|
1474
|
+
if (event.user_id) {
|
|
1475
|
+
metadata.user_id = event.user_id;
|
|
1476
|
+
}
|
|
1477
|
+
this.emit(eventName, data, metadata);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
handleInternalEvent(event) {
|
|
1481
|
+
var eventName = event.event;
|
|
1482
|
+
var data = event.data;
|
|
1483
|
+
switch (eventName) {
|
|
1484
|
+
case "pusher_internal:subscription_succeeded":
|
|
1485
|
+
this.handleSubscriptionSucceededEvent(event);
|
|
1486
|
+
break;
|
|
1487
|
+
case "pusher_internal:subscription_count":
|
|
1488
|
+
this.handleSubscriptionCountEvent(event);
|
|
1489
|
+
break;
|
|
1490
|
+
case "pusher_internal:member_added":
|
|
1491
|
+
var addedMember = this.members.addMember(data);
|
|
1492
|
+
this.emit("pusher:member_added", addedMember);
|
|
1493
|
+
break;
|
|
1494
|
+
case "pusher_internal:member_removed":
|
|
1495
|
+
var removedMember = this.members.removeMember(data);
|
|
1496
|
+
if (removedMember) {
|
|
1497
|
+
this.emit("pusher:member_removed", removedMember);
|
|
1498
|
+
}
|
|
1499
|
+
break;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
handleSubscriptionSucceededEvent(event) {
|
|
1503
|
+
this.subscriptionPending = false;
|
|
1504
|
+
this.subscribed = true;
|
|
1505
|
+
if (this.subscriptionCancelled) {
|
|
1506
|
+
this.pusher.unsubscribe(this.name);
|
|
1507
|
+
} else {
|
|
1508
|
+
this.members.onSubscription(event.data);
|
|
1509
|
+
this.emit("pusher:subscription_succeeded", this.members);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
/** Resets the channel state, including members map. For internal use only. */
|
|
1513
|
+
disconnect() {
|
|
1514
|
+
this.members.reset();
|
|
1515
|
+
super.disconnect();
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
class EncryptedChannel extends PrivateChannel {
|
|
1519
|
+
constructor(name, pusher, nacl2) {
|
|
1520
|
+
super(name, pusher);
|
|
1521
|
+
this.key = null;
|
|
1522
|
+
this.nacl = nacl2;
|
|
1523
|
+
}
|
|
1524
|
+
/** Authorizes the connection to use the channel.
|
|
1525
|
+
*
|
|
1526
|
+
* @param {String} socketId
|
|
1527
|
+
* @param {Function} callback
|
|
1528
|
+
*/
|
|
1529
|
+
authorize(socketId, callback) {
|
|
1530
|
+
super.authorize(
|
|
1531
|
+
socketId,
|
|
1532
|
+
(error, authData) => {
|
|
1533
|
+
if (error) {
|
|
1534
|
+
callback(error, authData);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
let sharedSecret = authData["shared_secret"];
|
|
1538
|
+
if (!sharedSecret) {
|
|
1539
|
+
callback(
|
|
1540
|
+
new Error(
|
|
1541
|
+
`No shared_secret key in auth payload for encrypted channel: ${this.name}`
|
|
1542
|
+
),
|
|
1543
|
+
null
|
|
1544
|
+
);
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
this.key = base64.decode(sharedSecret);
|
|
1548
|
+
delete authData["shared_secret"];
|
|
1549
|
+
callback(null, authData);
|
|
1550
|
+
}
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
trigger(event, data) {
|
|
1554
|
+
throw new UnsupportedFeature(
|
|
1555
|
+
"Client events are not currently supported for encrypted channels"
|
|
1556
|
+
);
|
|
1557
|
+
}
|
|
1558
|
+
/** Handles an event. For internal use only.
|
|
1559
|
+
*
|
|
1560
|
+
* @param {PusherEvent} event
|
|
1561
|
+
*/
|
|
1562
|
+
handleEvent(event) {
|
|
1563
|
+
var eventName = event.event;
|
|
1564
|
+
var data = event.data;
|
|
1565
|
+
if (eventName.indexOf("pusher_internal:") === 0 || eventName.indexOf("pusher:") === 0) {
|
|
1566
|
+
super.handleEvent(event);
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
this.handleEncryptedEvent(eventName, data);
|
|
1570
|
+
}
|
|
1571
|
+
handleEncryptedEvent(event, data) {
|
|
1572
|
+
if (!this.key) {
|
|
1573
|
+
Logger$1.debug(
|
|
1574
|
+
"Received encrypted event before key has been retrieved from the authEndpoint"
|
|
1575
|
+
);
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
if (!data.ciphertext || !data.nonce) {
|
|
1579
|
+
Logger$1.error(
|
|
1580
|
+
"Unexpected format for encrypted event, expected object with `ciphertext` and `nonce` fields, got: " + data
|
|
1581
|
+
);
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
let cipherText = base64.decode(data.ciphertext);
|
|
1585
|
+
if (cipherText.length < this.nacl.secretbox.overheadLength) {
|
|
1586
|
+
Logger$1.error(
|
|
1587
|
+
`Expected encrypted event ciphertext length to be ${this.nacl.secretbox.overheadLength}, got: ${cipherText.length}`
|
|
1588
|
+
);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
let nonce = base64.decode(data.nonce);
|
|
1592
|
+
if (nonce.length < this.nacl.secretbox.nonceLength) {
|
|
1593
|
+
Logger$1.error(
|
|
1594
|
+
`Expected encrypted event nonce length to be ${this.nacl.secretbox.nonceLength}, got: ${nonce.length}`
|
|
1595
|
+
);
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
let bytes = this.nacl.secretbox.open(cipherText, nonce, this.key);
|
|
1599
|
+
if (bytes === null) {
|
|
1600
|
+
Logger$1.debug(
|
|
1601
|
+
"Failed to decrypt an event, probably because it was encrypted with a different key. Fetching a new key from the authEndpoint..."
|
|
1602
|
+
);
|
|
1603
|
+
this.authorize(this.pusher.connection.socket_id, (error, authData) => {
|
|
1604
|
+
if (error) {
|
|
1605
|
+
Logger$1.error(
|
|
1606
|
+
`Failed to make a request to the authEndpoint: ${authData}. Unable to fetch new key, so dropping encrypted event`
|
|
1607
|
+
);
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
bytes = this.nacl.secretbox.open(cipherText, nonce, this.key);
|
|
1611
|
+
if (bytes === null) {
|
|
1612
|
+
Logger$1.error(
|
|
1613
|
+
`Failed to decrypt event with new key. Dropping encrypted event`
|
|
1614
|
+
);
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
this.emit(event, this.getDataToEmit(bytes));
|
|
1618
|
+
return;
|
|
1619
|
+
});
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1622
|
+
this.emit(event, this.getDataToEmit(bytes));
|
|
1623
|
+
}
|
|
1624
|
+
// Try and parse the decrypted bytes as JSON. If we can't parse it, just
|
|
1625
|
+
// return the utf-8 string
|
|
1626
|
+
getDataToEmit(bytes) {
|
|
1627
|
+
let raw = utf8.decode(bytes);
|
|
1628
|
+
try {
|
|
1629
|
+
return JSON.parse(raw);
|
|
1630
|
+
} catch {
|
|
1631
|
+
return raw;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
class ConnectionManager extends Dispatcher {
|
|
1636
|
+
constructor(key, options) {
|
|
1637
|
+
super();
|
|
1638
|
+
this.state = "initialized";
|
|
1639
|
+
this.connection = null;
|
|
1640
|
+
this.key = key;
|
|
1641
|
+
this.options = options;
|
|
1642
|
+
this.timeline = this.options.timeline;
|
|
1643
|
+
this.usingTLS = this.options.useTLS;
|
|
1644
|
+
this.errorCallbacks = this.buildErrorCallbacks();
|
|
1645
|
+
this.connectionCallbacks = this.buildConnectionCallbacks(
|
|
1646
|
+
this.errorCallbacks
|
|
1647
|
+
);
|
|
1648
|
+
this.handshakeCallbacks = this.buildHandshakeCallbacks(this.errorCallbacks);
|
|
1649
|
+
var Network2 = NodeJS.getNetwork();
|
|
1650
|
+
Network2.bind("online", () => {
|
|
1651
|
+
this.timeline.info({ netinfo: "online" });
|
|
1652
|
+
if (this.state === "connecting" || this.state === "unavailable") {
|
|
1653
|
+
this.retryIn(0);
|
|
1654
|
+
}
|
|
1655
|
+
});
|
|
1656
|
+
Network2.bind("offline", () => {
|
|
1657
|
+
this.timeline.info({ netinfo: "offline" });
|
|
1658
|
+
if (this.connection) {
|
|
1659
|
+
this.sendActivityCheck();
|
|
1660
|
+
}
|
|
1661
|
+
});
|
|
1662
|
+
this.updateStrategy();
|
|
1663
|
+
}
|
|
1664
|
+
/** Establishes a connection to Pusher.
|
|
1665
|
+
*
|
|
1666
|
+
* Does nothing when connection is already established. See top-level doc
|
|
1667
|
+
* to find events emitted on connection attempts.
|
|
1668
|
+
*/
|
|
1669
|
+
connect() {
|
|
1670
|
+
if (this.connection || this.runner) {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
if (!this.strategy.isSupported()) {
|
|
1674
|
+
this.updateState("failed");
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
this.updateState("connecting");
|
|
1678
|
+
this.startConnecting();
|
|
1679
|
+
this.setUnavailableTimer();
|
|
1680
|
+
}
|
|
1681
|
+
/** Sends raw data.
|
|
1682
|
+
*
|
|
1683
|
+
* @param {String} data
|
|
1684
|
+
*/
|
|
1685
|
+
send(data) {
|
|
1686
|
+
if (this.connection) {
|
|
1687
|
+
return this.connection.send(data);
|
|
1688
|
+
} else {
|
|
1689
|
+
return false;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
/** Sends an event.
|
|
1693
|
+
*
|
|
1694
|
+
* @param {String} name
|
|
1695
|
+
* @param {String} data
|
|
1696
|
+
* @param {String} [channel]
|
|
1697
|
+
* @returns {Boolean} whether message was sent or not
|
|
1698
|
+
*/
|
|
1699
|
+
send_event(name, data, channel) {
|
|
1700
|
+
if (this.connection) {
|
|
1701
|
+
return this.connection.send_event(name, data, channel);
|
|
1702
|
+
} else {
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
/** Closes the connection. */
|
|
1707
|
+
disconnect() {
|
|
1708
|
+
this.disconnectInternally();
|
|
1709
|
+
this.updateState("disconnected");
|
|
1710
|
+
}
|
|
1711
|
+
isUsingTLS() {
|
|
1712
|
+
return this.usingTLS;
|
|
1713
|
+
}
|
|
1714
|
+
startConnecting() {
|
|
1715
|
+
var callback = (error, handshake) => {
|
|
1716
|
+
if (error) {
|
|
1717
|
+
this.runner = this.strategy.connect(0, callback);
|
|
1718
|
+
} else {
|
|
1719
|
+
if (handshake.action === "error") {
|
|
1720
|
+
this.emit("error", {
|
|
1721
|
+
type: "HandshakeError",
|
|
1722
|
+
error: handshake.error
|
|
1723
|
+
});
|
|
1724
|
+
this.timeline.error({ handshakeError: handshake.error });
|
|
1725
|
+
} else {
|
|
1726
|
+
this.abortConnecting();
|
|
1727
|
+
this.handshakeCallbacks[handshake.action](handshake);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
this.runner = this.strategy.connect(0, callback);
|
|
1732
|
+
}
|
|
1733
|
+
abortConnecting() {
|
|
1734
|
+
if (this.runner) {
|
|
1735
|
+
this.runner.abort();
|
|
1736
|
+
this.runner = null;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
disconnectInternally() {
|
|
1740
|
+
this.abortConnecting();
|
|
1741
|
+
this.clearRetryTimer();
|
|
1742
|
+
this.clearUnavailableTimer();
|
|
1743
|
+
if (this.connection) {
|
|
1744
|
+
var connection = this.abandonConnection();
|
|
1745
|
+
connection.close();
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
updateStrategy() {
|
|
1749
|
+
this.strategy = this.options.getStrategy({
|
|
1750
|
+
key: this.key,
|
|
1751
|
+
timeline: this.timeline,
|
|
1752
|
+
useTLS: this.usingTLS
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1755
|
+
retryIn(delay) {
|
|
1756
|
+
this.timeline.info({ action: "retry", delay });
|
|
1757
|
+
if (delay > 0) {
|
|
1758
|
+
this.emit("connecting_in", Math.round(delay / 1e3));
|
|
1759
|
+
}
|
|
1760
|
+
this.retryTimer = new OneOffTimer(delay || 0, () => {
|
|
1761
|
+
this.disconnectInternally();
|
|
1762
|
+
this.connect();
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
clearRetryTimer() {
|
|
1766
|
+
if (this.retryTimer) {
|
|
1767
|
+
this.retryTimer.ensureAborted();
|
|
1768
|
+
this.retryTimer = null;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
setUnavailableTimer() {
|
|
1772
|
+
this.unavailableTimer = new OneOffTimer(this.options.unavailableTimeout, () => {
|
|
1773
|
+
this.updateState("unavailable");
|
|
1774
|
+
});
|
|
1775
|
+
}
|
|
1776
|
+
clearUnavailableTimer() {
|
|
1777
|
+
if (this.unavailableTimer) {
|
|
1778
|
+
this.unavailableTimer.ensureAborted();
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
sendActivityCheck() {
|
|
1782
|
+
this.stopActivityCheck();
|
|
1783
|
+
this.connection.ping();
|
|
1784
|
+
this.activityTimer = new OneOffTimer(this.options.pongTimeout, () => {
|
|
1785
|
+
this.timeline.error({ pong_timed_out: this.options.pongTimeout });
|
|
1786
|
+
this.retryIn(0);
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
resetActivityCheck() {
|
|
1790
|
+
this.stopActivityCheck();
|
|
1791
|
+
if (this.connection && !this.connection.handlesActivityChecks()) {
|
|
1792
|
+
this.activityTimer = new OneOffTimer(this.activityTimeout, () => {
|
|
1793
|
+
this.sendActivityCheck();
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
stopActivityCheck() {
|
|
1798
|
+
if (this.activityTimer) {
|
|
1799
|
+
this.activityTimer.ensureAborted();
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
buildConnectionCallbacks(errorCallbacks) {
|
|
1803
|
+
return extend({}, errorCallbacks, {
|
|
1804
|
+
message: (message) => {
|
|
1805
|
+
this.resetActivityCheck();
|
|
1806
|
+
this.emit("message", message);
|
|
1807
|
+
},
|
|
1808
|
+
ping: () => {
|
|
1809
|
+
this.send_event("pusher:pong", {});
|
|
1810
|
+
},
|
|
1811
|
+
activity: () => {
|
|
1812
|
+
this.resetActivityCheck();
|
|
1813
|
+
},
|
|
1814
|
+
error: (error) => {
|
|
1815
|
+
this.emit("error", error);
|
|
1816
|
+
},
|
|
1817
|
+
closed: () => {
|
|
1818
|
+
this.abandonConnection();
|
|
1819
|
+
if (this.shouldRetry()) {
|
|
1820
|
+
this.retryIn(1e3);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
buildHandshakeCallbacks(errorCallbacks) {
|
|
1826
|
+
return extend({}, errorCallbacks, {
|
|
1827
|
+
connected: (handshake) => {
|
|
1828
|
+
this.activityTimeout = Math.min(
|
|
1829
|
+
this.options.activityTimeout,
|
|
1830
|
+
handshake.activityTimeout,
|
|
1831
|
+
handshake.connection.activityTimeout || Infinity
|
|
1832
|
+
);
|
|
1833
|
+
this.clearUnavailableTimer();
|
|
1834
|
+
this.setConnection(handshake.connection);
|
|
1835
|
+
this.socket_id = this.connection.id;
|
|
1836
|
+
this.updateState("connected", { socket_id: this.socket_id });
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
}
|
|
1840
|
+
buildErrorCallbacks() {
|
|
1841
|
+
let withErrorEmitted = (callback) => {
|
|
1842
|
+
return (result) => {
|
|
1843
|
+
if (result.error) {
|
|
1844
|
+
this.emit("error", { type: "WebSocketError", error: result.error });
|
|
1845
|
+
}
|
|
1846
|
+
callback(result);
|
|
1847
|
+
};
|
|
1848
|
+
};
|
|
1849
|
+
return {
|
|
1850
|
+
tls_only: withErrorEmitted(() => {
|
|
1851
|
+
this.usingTLS = true;
|
|
1852
|
+
this.updateStrategy();
|
|
1853
|
+
this.retryIn(0);
|
|
1854
|
+
}),
|
|
1855
|
+
refused: withErrorEmitted(() => {
|
|
1856
|
+
this.disconnect();
|
|
1857
|
+
}),
|
|
1858
|
+
backoff: withErrorEmitted(() => {
|
|
1859
|
+
this.retryIn(1e3);
|
|
1860
|
+
}),
|
|
1861
|
+
retry: withErrorEmitted(() => {
|
|
1862
|
+
this.retryIn(0);
|
|
1863
|
+
})
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
setConnection(connection) {
|
|
1867
|
+
this.connection = connection;
|
|
1868
|
+
for (var event in this.connectionCallbacks) {
|
|
1869
|
+
this.connection.bind(event, this.connectionCallbacks[event]);
|
|
1870
|
+
}
|
|
1871
|
+
this.resetActivityCheck();
|
|
1872
|
+
}
|
|
1873
|
+
abandonConnection() {
|
|
1874
|
+
if (!this.connection) {
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
this.stopActivityCheck();
|
|
1878
|
+
for (var event in this.connectionCallbacks) {
|
|
1879
|
+
this.connection.unbind(event, this.connectionCallbacks[event]);
|
|
1880
|
+
}
|
|
1881
|
+
var connection = this.connection;
|
|
1882
|
+
this.connection = null;
|
|
1883
|
+
return connection;
|
|
1884
|
+
}
|
|
1885
|
+
updateState(newState, data) {
|
|
1886
|
+
var previousState = this.state;
|
|
1887
|
+
this.state = newState;
|
|
1888
|
+
if (previousState !== newState) {
|
|
1889
|
+
var newStateDescription = newState;
|
|
1890
|
+
if (newStateDescription === "connected") {
|
|
1891
|
+
newStateDescription += " with new socket ID " + data.socket_id;
|
|
1892
|
+
}
|
|
1893
|
+
Logger$1.debug(
|
|
1894
|
+
"State changed",
|
|
1895
|
+
previousState + " -> " + newStateDescription
|
|
1896
|
+
);
|
|
1897
|
+
this.timeline.info({ state: newState, params: data });
|
|
1898
|
+
this.emit("state_change", { previous: previousState, current: newState });
|
|
1899
|
+
this.emit(newState, data);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
shouldRetry() {
|
|
1903
|
+
return this.state === "connecting" || this.state === "connected";
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
class Channels {
|
|
1907
|
+
constructor() {
|
|
1908
|
+
this.channels = {};
|
|
1909
|
+
}
|
|
1910
|
+
/** Creates or retrieves an existing channel by its name.
|
|
1911
|
+
*
|
|
1912
|
+
* @param {String} name
|
|
1913
|
+
* @param {Pusher} pusher
|
|
1914
|
+
* @return {Channel}
|
|
1915
|
+
*/
|
|
1916
|
+
add(name, pusher) {
|
|
1917
|
+
if (!this.channels[name]) {
|
|
1918
|
+
this.channels[name] = createChannel(name, pusher);
|
|
1919
|
+
}
|
|
1920
|
+
return this.channels[name];
|
|
1921
|
+
}
|
|
1922
|
+
/** Returns a list of all channels
|
|
1923
|
+
*
|
|
1924
|
+
* @return {Array}
|
|
1925
|
+
*/
|
|
1926
|
+
all() {
|
|
1927
|
+
return values(this.channels);
|
|
1928
|
+
}
|
|
1929
|
+
/** Finds a channel by its name.
|
|
1930
|
+
*
|
|
1931
|
+
* @param {String} name
|
|
1932
|
+
* @return {Channel} channel or null if it doesn't exist
|
|
1933
|
+
*/
|
|
1934
|
+
find(name) {
|
|
1935
|
+
return this.channels[name];
|
|
1936
|
+
}
|
|
1937
|
+
/** Removes a channel from the map.
|
|
1938
|
+
*
|
|
1939
|
+
* @param {String} name
|
|
1940
|
+
*/
|
|
1941
|
+
remove(name) {
|
|
1942
|
+
var channel = this.channels[name];
|
|
1943
|
+
delete this.channels[name];
|
|
1944
|
+
return channel;
|
|
1945
|
+
}
|
|
1946
|
+
/** Proxies disconnection signal to all channels. */
|
|
1947
|
+
disconnect() {
|
|
1948
|
+
objectApply(this.channels, function(channel) {
|
|
1949
|
+
channel.disconnect();
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
function createChannel(name, pusher) {
|
|
1954
|
+
if (name.indexOf("private-encrypted-") === 0) {
|
|
1955
|
+
if (pusher.config.nacl) {
|
|
1956
|
+
return Factory.createEncryptedChannel(name, pusher, pusher.config.nacl);
|
|
1957
|
+
}
|
|
1958
|
+
let errMsg = "Tried to subscribe to a private-encrypted- channel but no nacl implementation available";
|
|
1959
|
+
let suffix = UrlStore.buildLogSuffix("encryptedChannelSupport");
|
|
1960
|
+
throw new UnsupportedFeature(`${errMsg}. ${suffix}`);
|
|
1961
|
+
} else if (name.indexOf("private-") === 0) {
|
|
1962
|
+
return Factory.createPrivateChannel(name, pusher);
|
|
1963
|
+
} else if (name.indexOf("presence-") === 0) {
|
|
1964
|
+
return Factory.createPresenceChannel(name, pusher);
|
|
1965
|
+
} else if (name.indexOf("#") === 0) {
|
|
1966
|
+
throw new BadChannelName(
|
|
1967
|
+
'Cannot create a channel with name "' + name + '".'
|
|
1968
|
+
);
|
|
1969
|
+
} else {
|
|
1970
|
+
return Factory.createChannel(name, pusher);
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
var Factory = {
|
|
1974
|
+
createChannels() {
|
|
1975
|
+
return new Channels();
|
|
1976
|
+
},
|
|
1977
|
+
createConnectionManager(key, options) {
|
|
1978
|
+
return new ConnectionManager(key, options);
|
|
1979
|
+
},
|
|
1980
|
+
createChannel(name, pusher) {
|
|
1981
|
+
return new Channel(name, pusher);
|
|
1982
|
+
},
|
|
1983
|
+
createPrivateChannel(name, pusher) {
|
|
1984
|
+
return new PrivateChannel(name, pusher);
|
|
1985
|
+
},
|
|
1986
|
+
createPresenceChannel(name, pusher) {
|
|
1987
|
+
return new PresenceChannel(name, pusher);
|
|
1988
|
+
},
|
|
1989
|
+
createEncryptedChannel(name, pusher, nacl2) {
|
|
1990
|
+
return new EncryptedChannel(name, pusher, nacl2);
|
|
1991
|
+
},
|
|
1992
|
+
createTimelineSender(timeline, options) {
|
|
1993
|
+
return new TimelineSender(timeline, options);
|
|
1994
|
+
},
|
|
1995
|
+
createHandshake(transport, callback) {
|
|
1996
|
+
return new Handshake(transport, callback);
|
|
1997
|
+
},
|
|
1998
|
+
createAssistantToTheTransportManager(manager, transport, options) {
|
|
1999
|
+
return new AssistantToTheTransportManager(manager, transport, options);
|
|
2000
|
+
}
|
|
2001
|
+
};
|
|
2002
|
+
class TransportManager {
|
|
2003
|
+
constructor(options) {
|
|
2004
|
+
this.options = options || {};
|
|
2005
|
+
this.livesLeft = this.options.lives || Infinity;
|
|
2006
|
+
}
|
|
2007
|
+
/** Creates a assistant for the transport.
|
|
2008
|
+
*
|
|
2009
|
+
* @param {Transport} transport
|
|
2010
|
+
* @returns {AssistantToTheTransportManager}
|
|
2011
|
+
*/
|
|
2012
|
+
getAssistant(transport) {
|
|
2013
|
+
return Factory.createAssistantToTheTransportManager(this, transport, {
|
|
2014
|
+
minPingDelay: this.options.minPingDelay,
|
|
2015
|
+
maxPingDelay: this.options.maxPingDelay
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
/** Returns whether the transport has any lives left.
|
|
2019
|
+
*
|
|
2020
|
+
* @returns {Boolean}
|
|
2021
|
+
*/
|
|
2022
|
+
isAlive() {
|
|
2023
|
+
return this.livesLeft > 0;
|
|
2024
|
+
}
|
|
2025
|
+
/** Takes one life from the transport. */
|
|
2026
|
+
reportDeath() {
|
|
2027
|
+
this.livesLeft -= 1;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
class SequentialStrategy {
|
|
2031
|
+
constructor(strategies, options) {
|
|
2032
|
+
this.strategies = strategies;
|
|
2033
|
+
this.loop = Boolean(options.loop);
|
|
2034
|
+
this.failFast = Boolean(options.failFast);
|
|
2035
|
+
this.timeout = options.timeout;
|
|
2036
|
+
this.timeoutLimit = options.timeoutLimit;
|
|
2037
|
+
}
|
|
2038
|
+
isSupported() {
|
|
2039
|
+
return any(this.strategies, Util.method("isSupported"));
|
|
2040
|
+
}
|
|
2041
|
+
connect(minPriority, callback) {
|
|
2042
|
+
var strategies = this.strategies;
|
|
2043
|
+
var current = 0;
|
|
2044
|
+
var timeout = this.timeout;
|
|
2045
|
+
var runner = null;
|
|
2046
|
+
var tryNextStrategy = (error, handshake) => {
|
|
2047
|
+
if (handshake) {
|
|
2048
|
+
callback(null, handshake);
|
|
2049
|
+
} else {
|
|
2050
|
+
current = current + 1;
|
|
2051
|
+
if (this.loop) {
|
|
2052
|
+
current = current % strategies.length;
|
|
2053
|
+
}
|
|
2054
|
+
if (current < strategies.length) {
|
|
2055
|
+
if (timeout) {
|
|
2056
|
+
timeout = timeout * 2;
|
|
2057
|
+
if (this.timeoutLimit) {
|
|
2058
|
+
timeout = Math.min(timeout, this.timeoutLimit);
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
runner = this.tryStrategy(
|
|
2062
|
+
strategies[current],
|
|
2063
|
+
minPriority,
|
|
2064
|
+
{ timeout, failFast: this.failFast },
|
|
2065
|
+
tryNextStrategy
|
|
2066
|
+
);
|
|
2067
|
+
} else {
|
|
2068
|
+
callback(true);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
runner = this.tryStrategy(
|
|
2073
|
+
strategies[current],
|
|
2074
|
+
minPriority,
|
|
2075
|
+
{ timeout, failFast: this.failFast },
|
|
2076
|
+
tryNextStrategy
|
|
2077
|
+
);
|
|
2078
|
+
return {
|
|
2079
|
+
abort: function() {
|
|
2080
|
+
runner.abort();
|
|
2081
|
+
},
|
|
2082
|
+
forceMinPriority: function(p) {
|
|
2083
|
+
minPriority = p;
|
|
2084
|
+
if (runner) {
|
|
2085
|
+
runner.forceMinPriority(p);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
tryStrategy(strategy, minPriority, options, callback) {
|
|
2091
|
+
var timer = null;
|
|
2092
|
+
var runner = null;
|
|
2093
|
+
if (options.timeout > 0) {
|
|
2094
|
+
timer = new OneOffTimer(options.timeout, function() {
|
|
2095
|
+
runner.abort();
|
|
2096
|
+
callback(true);
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
runner = strategy.connect(minPriority, function(error, handshake) {
|
|
2100
|
+
if (error && timer && timer.isRunning() && !options.failFast) {
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
if (timer) {
|
|
2104
|
+
timer.ensureAborted();
|
|
2105
|
+
}
|
|
2106
|
+
callback(error, handshake);
|
|
2107
|
+
});
|
|
2108
|
+
return {
|
|
2109
|
+
abort: function() {
|
|
2110
|
+
if (timer) {
|
|
2111
|
+
timer.ensureAborted();
|
|
2112
|
+
}
|
|
2113
|
+
runner.abort();
|
|
2114
|
+
},
|
|
2115
|
+
forceMinPriority: function(p) {
|
|
2116
|
+
runner.forceMinPriority(p);
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
class BestConnectedEverStrategy {
|
|
2122
|
+
constructor(strategies) {
|
|
2123
|
+
this.strategies = strategies;
|
|
2124
|
+
}
|
|
2125
|
+
isSupported() {
|
|
2126
|
+
return any(this.strategies, Util.method("isSupported"));
|
|
2127
|
+
}
|
|
2128
|
+
connect(minPriority, callback) {
|
|
2129
|
+
return connect(this.strategies, minPriority, function(i, runners) {
|
|
2130
|
+
return function(error, handshake) {
|
|
2131
|
+
runners[i].error = error;
|
|
2132
|
+
if (error) {
|
|
2133
|
+
if (allRunnersFailed(runners)) {
|
|
2134
|
+
callback(true);
|
|
2135
|
+
}
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
apply(runners, function(runner) {
|
|
2139
|
+
runner.forceMinPriority(handshake.transport.priority);
|
|
2140
|
+
});
|
|
2141
|
+
callback(null, handshake);
|
|
2142
|
+
};
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
function connect(strategies, minPriority, callbackBuilder) {
|
|
2147
|
+
var runners = map(strategies, function(strategy, i, _, rs) {
|
|
2148
|
+
return strategy.connect(minPriority, callbackBuilder(i, rs));
|
|
2149
|
+
});
|
|
2150
|
+
return {
|
|
2151
|
+
abort: function() {
|
|
2152
|
+
apply(runners, abortRunner);
|
|
2153
|
+
},
|
|
2154
|
+
forceMinPriority: function(p) {
|
|
2155
|
+
apply(runners, function(runner) {
|
|
2156
|
+
runner.forceMinPriority(p);
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
function allRunnersFailed(runners) {
|
|
2162
|
+
return all(runners, function(runner) {
|
|
2163
|
+
return Boolean(runner.error);
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2166
|
+
function abortRunner(runner) {
|
|
2167
|
+
if (!runner.error && !runner.aborted) {
|
|
2168
|
+
runner.abort();
|
|
2169
|
+
runner.aborted = true;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
class WebSocketPrioritizedCachedStrategy {
|
|
2173
|
+
constructor(strategy, transports, options) {
|
|
2174
|
+
this.strategy = strategy;
|
|
2175
|
+
this.transports = transports;
|
|
2176
|
+
this.ttl = options.ttl || 1800 * 1e3;
|
|
2177
|
+
this.usingTLS = options.useTLS;
|
|
2178
|
+
this.timeline = options.timeline;
|
|
2179
|
+
}
|
|
2180
|
+
isSupported() {
|
|
2181
|
+
return this.strategy.isSupported();
|
|
2182
|
+
}
|
|
2183
|
+
connect(minPriority, callback) {
|
|
2184
|
+
var usingTLS = this.usingTLS;
|
|
2185
|
+
var info = fetchTransportCache(usingTLS);
|
|
2186
|
+
var cacheSkipCount = info && info.cacheSkipCount ? info.cacheSkipCount : 0;
|
|
2187
|
+
var strategies = [this.strategy];
|
|
2188
|
+
if (info && info.timestamp + this.ttl >= Util.now()) {
|
|
2189
|
+
var transport = this.transports[info.transport];
|
|
2190
|
+
if (transport) {
|
|
2191
|
+
if (["ws", "wss"].includes(info.transport) || cacheSkipCount > 3) {
|
|
2192
|
+
this.timeline.info({
|
|
2193
|
+
cached: true,
|
|
2194
|
+
transport: info.transport,
|
|
2195
|
+
latency: info.latency
|
|
2196
|
+
});
|
|
2197
|
+
strategies.push(
|
|
2198
|
+
new SequentialStrategy([transport], {
|
|
2199
|
+
timeout: info.latency * 2 + 1e3,
|
|
2200
|
+
failFast: true
|
|
2201
|
+
})
|
|
2202
|
+
);
|
|
2203
|
+
} else {
|
|
2204
|
+
cacheSkipCount++;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
var startTimestamp = Util.now();
|
|
2209
|
+
var runner = strategies.pop().connect(minPriority, function cb(error, handshake) {
|
|
2210
|
+
if (error) {
|
|
2211
|
+
flushTransportCache(usingTLS);
|
|
2212
|
+
if (strategies.length > 0) {
|
|
2213
|
+
startTimestamp = Util.now();
|
|
2214
|
+
runner = strategies.pop().connect(minPriority, cb);
|
|
2215
|
+
} else {
|
|
2216
|
+
callback(error);
|
|
2217
|
+
}
|
|
2218
|
+
} else {
|
|
2219
|
+
storeTransportCache(
|
|
2220
|
+
usingTLS,
|
|
2221
|
+
handshake.transport.name,
|
|
2222
|
+
Util.now() - startTimestamp,
|
|
2223
|
+
cacheSkipCount
|
|
2224
|
+
);
|
|
2225
|
+
callback(null, handshake);
|
|
2226
|
+
}
|
|
2227
|
+
});
|
|
2228
|
+
return {
|
|
2229
|
+
abort: function() {
|
|
2230
|
+
runner.abort();
|
|
2231
|
+
},
|
|
2232
|
+
forceMinPriority: function(p) {
|
|
2233
|
+
minPriority = p;
|
|
2234
|
+
if (runner) {
|
|
2235
|
+
runner.forceMinPriority(p);
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
function getTransportCacheKey(usingTLS) {
|
|
2242
|
+
return "pusherTransport" + (usingTLS ? "TLS" : "NonTLS");
|
|
2243
|
+
}
|
|
2244
|
+
function fetchTransportCache(usingTLS) {
|
|
2245
|
+
var storage = NodeJS.getLocalStorage();
|
|
2246
|
+
if (storage) {
|
|
2247
|
+
try {
|
|
2248
|
+
var serializedCache = storage[getTransportCacheKey(usingTLS)];
|
|
2249
|
+
if (serializedCache) {
|
|
2250
|
+
return JSON.parse(serializedCache);
|
|
2251
|
+
}
|
|
2252
|
+
} catch (e) {
|
|
2253
|
+
flushTransportCache(usingTLS);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
return null;
|
|
2257
|
+
}
|
|
2258
|
+
function storeTransportCache(usingTLS, transport, latency, cacheSkipCount) {
|
|
2259
|
+
var storage = NodeJS.getLocalStorage();
|
|
2260
|
+
if (storage) {
|
|
2261
|
+
try {
|
|
2262
|
+
storage[getTransportCacheKey(usingTLS)] = safeJSONStringify({
|
|
2263
|
+
timestamp: Util.now(),
|
|
2264
|
+
transport,
|
|
2265
|
+
latency,
|
|
2266
|
+
cacheSkipCount
|
|
2267
|
+
});
|
|
2268
|
+
} catch (e) {
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
function flushTransportCache(usingTLS) {
|
|
2273
|
+
var storage = NodeJS.getLocalStorage();
|
|
2274
|
+
if (storage) {
|
|
2275
|
+
try {
|
|
2276
|
+
delete storage[getTransportCacheKey(usingTLS)];
|
|
2277
|
+
} catch (e) {
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
class DelayedStrategy {
|
|
2282
|
+
constructor(strategy, { delay: number }) {
|
|
2283
|
+
this.strategy = strategy;
|
|
2284
|
+
this.options = { delay: number };
|
|
2285
|
+
}
|
|
2286
|
+
isSupported() {
|
|
2287
|
+
return this.strategy.isSupported();
|
|
2288
|
+
}
|
|
2289
|
+
connect(minPriority, callback) {
|
|
2290
|
+
var strategy = this.strategy;
|
|
2291
|
+
var runner;
|
|
2292
|
+
var timer = new OneOffTimer(this.options.delay, function() {
|
|
2293
|
+
runner = strategy.connect(minPriority, callback);
|
|
2294
|
+
});
|
|
2295
|
+
return {
|
|
2296
|
+
abort: function() {
|
|
2297
|
+
timer.ensureAborted();
|
|
2298
|
+
if (runner) {
|
|
2299
|
+
runner.abort();
|
|
2300
|
+
}
|
|
2301
|
+
},
|
|
2302
|
+
forceMinPriority: function(p) {
|
|
2303
|
+
minPriority = p;
|
|
2304
|
+
if (runner) {
|
|
2305
|
+
runner.forceMinPriority(p);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
class IfStrategy {
|
|
2312
|
+
constructor(test, trueBranch, falseBranch) {
|
|
2313
|
+
this.test = test;
|
|
2314
|
+
this.trueBranch = trueBranch;
|
|
2315
|
+
this.falseBranch = falseBranch;
|
|
2316
|
+
}
|
|
2317
|
+
isSupported() {
|
|
2318
|
+
var branch = this.test() ? this.trueBranch : this.falseBranch;
|
|
2319
|
+
return branch.isSupported();
|
|
2320
|
+
}
|
|
2321
|
+
connect(minPriority, callback) {
|
|
2322
|
+
var branch = this.test() ? this.trueBranch : this.falseBranch;
|
|
2323
|
+
return branch.connect(minPriority, callback);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
class FirstConnectedStrategy {
|
|
2327
|
+
constructor(strategy) {
|
|
2328
|
+
this.strategy = strategy;
|
|
2329
|
+
}
|
|
2330
|
+
isSupported() {
|
|
2331
|
+
return this.strategy.isSupported();
|
|
2332
|
+
}
|
|
2333
|
+
connect(minPriority, callback) {
|
|
2334
|
+
var runner = this.strategy.connect(
|
|
2335
|
+
minPriority,
|
|
2336
|
+
function(error, handshake) {
|
|
2337
|
+
if (handshake) {
|
|
2338
|
+
runner.abort();
|
|
2339
|
+
}
|
|
2340
|
+
callback(error, handshake);
|
|
2341
|
+
}
|
|
2342
|
+
);
|
|
2343
|
+
return runner;
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
function testSupportsStrategy(strategy) {
|
|
2347
|
+
return function() {
|
|
2348
|
+
return strategy.isSupported();
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
var getDefaultStrategy$1 = function(config2, baseOptions, defineTransport2) {
|
|
2352
|
+
var definedTransports = {};
|
|
2353
|
+
function defineTransportStrategy(name, type, priority, options, manager) {
|
|
2354
|
+
var transport = defineTransport2(
|
|
2355
|
+
config2,
|
|
2356
|
+
name,
|
|
2357
|
+
type,
|
|
2358
|
+
priority,
|
|
2359
|
+
options,
|
|
2360
|
+
manager
|
|
2361
|
+
);
|
|
2362
|
+
definedTransports[name] = transport;
|
|
2363
|
+
return transport;
|
|
2364
|
+
}
|
|
2365
|
+
var ws_options = Object.assign({}, baseOptions, {
|
|
2366
|
+
hostNonTLS: config2.wsHost + ":" + config2.wsPort,
|
|
2367
|
+
hostTLS: config2.wsHost + ":" + config2.wssPort,
|
|
2368
|
+
httpPath: config2.wsPath
|
|
2369
|
+
});
|
|
2370
|
+
var wss_options = extend({}, ws_options, {
|
|
2371
|
+
useTLS: true
|
|
2372
|
+
});
|
|
2373
|
+
var http_options = Object.assign({}, baseOptions, {
|
|
2374
|
+
hostNonTLS: config2.httpHost + ":" + config2.httpPort,
|
|
2375
|
+
hostTLS: config2.httpHost + ":" + config2.httpsPort,
|
|
2376
|
+
httpPath: config2.httpPath
|
|
2377
|
+
});
|
|
2378
|
+
var timeouts = {
|
|
2379
|
+
loop: true,
|
|
2380
|
+
timeout: 15e3,
|
|
2381
|
+
timeoutLimit: 6e4
|
|
2382
|
+
};
|
|
2383
|
+
var ws_manager = new TransportManager({
|
|
2384
|
+
minPingDelay: 1e4,
|
|
2385
|
+
maxPingDelay: config2.activityTimeout
|
|
2386
|
+
});
|
|
2387
|
+
var streaming_manager = new TransportManager({
|
|
2388
|
+
lives: 2,
|
|
2389
|
+
minPingDelay: 1e4,
|
|
2390
|
+
maxPingDelay: config2.activityTimeout
|
|
2391
|
+
});
|
|
2392
|
+
var ws_transport = defineTransportStrategy(
|
|
2393
|
+
"ws",
|
|
2394
|
+
"ws",
|
|
2395
|
+
3,
|
|
2396
|
+
ws_options,
|
|
2397
|
+
ws_manager
|
|
2398
|
+
);
|
|
2399
|
+
var wss_transport = defineTransportStrategy(
|
|
2400
|
+
"wss",
|
|
2401
|
+
"ws",
|
|
2402
|
+
3,
|
|
2403
|
+
wss_options,
|
|
2404
|
+
ws_manager
|
|
2405
|
+
);
|
|
2406
|
+
var xhr_streaming_transport = defineTransportStrategy(
|
|
2407
|
+
"xhr_streaming",
|
|
2408
|
+
"xhr_streaming",
|
|
2409
|
+
1,
|
|
2410
|
+
http_options,
|
|
2411
|
+
streaming_manager
|
|
2412
|
+
);
|
|
2413
|
+
var xhr_polling_transport = defineTransportStrategy(
|
|
2414
|
+
"xhr_polling",
|
|
2415
|
+
"xhr_polling",
|
|
2416
|
+
1,
|
|
2417
|
+
http_options
|
|
2418
|
+
);
|
|
2419
|
+
var ws_loop = new SequentialStrategy([ws_transport], timeouts);
|
|
2420
|
+
var wss_loop = new SequentialStrategy([wss_transport], timeouts);
|
|
2421
|
+
var streaming_loop = new SequentialStrategy(
|
|
2422
|
+
[xhr_streaming_transport],
|
|
2423
|
+
timeouts
|
|
2424
|
+
);
|
|
2425
|
+
var polling_loop = new SequentialStrategy([xhr_polling_transport], timeouts);
|
|
2426
|
+
var http_loop = new SequentialStrategy(
|
|
2427
|
+
[
|
|
2428
|
+
new IfStrategy(
|
|
2429
|
+
testSupportsStrategy(streaming_loop),
|
|
2430
|
+
new BestConnectedEverStrategy([
|
|
2431
|
+
streaming_loop,
|
|
2432
|
+
new DelayedStrategy(polling_loop, { delay: 4e3 })
|
|
2433
|
+
]),
|
|
2434
|
+
polling_loop
|
|
2435
|
+
)
|
|
2436
|
+
],
|
|
2437
|
+
timeouts
|
|
2438
|
+
);
|
|
2439
|
+
var wsStrategy;
|
|
2440
|
+
if (baseOptions.useTLS) {
|
|
2441
|
+
wsStrategy = new BestConnectedEverStrategy([
|
|
2442
|
+
ws_loop,
|
|
2443
|
+
new DelayedStrategy(http_loop, { delay: 2e3 })
|
|
2444
|
+
]);
|
|
2445
|
+
} else {
|
|
2446
|
+
wsStrategy = new BestConnectedEverStrategy([
|
|
2447
|
+
ws_loop,
|
|
2448
|
+
new DelayedStrategy(wss_loop, { delay: 2e3 }),
|
|
2449
|
+
new DelayedStrategy(http_loop, { delay: 5e3 })
|
|
2450
|
+
]);
|
|
2451
|
+
}
|
|
2452
|
+
return new WebSocketPrioritizedCachedStrategy(
|
|
2453
|
+
new FirstConnectedStrategy(
|
|
2454
|
+
new IfStrategy(testSupportsStrategy(ws_transport), wsStrategy, http_loop)
|
|
2455
|
+
),
|
|
2456
|
+
definedTransports,
|
|
2457
|
+
{
|
|
2458
|
+
ttl: 18e5,
|
|
2459
|
+
timeline: baseOptions.timeline,
|
|
2460
|
+
useTLS: baseOptions.useTLS
|
|
2461
|
+
}
|
|
2462
|
+
);
|
|
2463
|
+
};
|
|
2464
|
+
function transportConnectionInitializer$1() {
|
|
2465
|
+
var self = this;
|
|
2466
|
+
self.timeline.info(
|
|
2467
|
+
self.buildTimelineMessage({
|
|
2468
|
+
transport: self.name + (self.options.useTLS ? "s" : "")
|
|
2469
|
+
})
|
|
2470
|
+
);
|
|
2471
|
+
if (self.hooks.isInitialized()) {
|
|
2472
|
+
self.changeState("initialized");
|
|
2473
|
+
} else {
|
|
2474
|
+
self.onClose();
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
const MAX_BUFFER_LENGTH = 256 * 1024;
|
|
2478
|
+
class HTTPRequest extends Dispatcher {
|
|
2479
|
+
constructor(hooks2, method, url) {
|
|
2480
|
+
super();
|
|
2481
|
+
this.hooks = hooks2;
|
|
2482
|
+
this.method = method;
|
|
2483
|
+
this.url = url;
|
|
2484
|
+
}
|
|
2485
|
+
start(payload) {
|
|
2486
|
+
this.position = 0;
|
|
2487
|
+
this.xhr = this.hooks.getRequest(this);
|
|
2488
|
+
this.unloader = () => {
|
|
2489
|
+
this.close();
|
|
2490
|
+
};
|
|
2491
|
+
NodeJS.addUnloadListener(this.unloader);
|
|
2492
|
+
this.xhr.open(this.method, this.url, true);
|
|
2493
|
+
if (this.xhr.setRequestHeader) {
|
|
2494
|
+
this.xhr.setRequestHeader("Content-Type", "application/json");
|
|
2495
|
+
}
|
|
2496
|
+
this.xhr.send(payload);
|
|
2497
|
+
}
|
|
2498
|
+
close() {
|
|
2499
|
+
if (this.unloader) {
|
|
2500
|
+
NodeJS.removeUnloadListener(this.unloader);
|
|
2501
|
+
this.unloader = null;
|
|
2502
|
+
}
|
|
2503
|
+
if (this.xhr) {
|
|
2504
|
+
this.hooks.abortRequest(this.xhr);
|
|
2505
|
+
this.xhr = null;
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
onChunk(status, data) {
|
|
2509
|
+
while (true) {
|
|
2510
|
+
var chunk = this.advanceBuffer(data);
|
|
2511
|
+
if (chunk) {
|
|
2512
|
+
this.emit("chunk", { status, data: chunk });
|
|
2513
|
+
} else {
|
|
2514
|
+
break;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
if (this.isBufferTooLong(data)) {
|
|
2518
|
+
this.emit("buffer_too_long");
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
advanceBuffer(buffer) {
|
|
2522
|
+
var unreadData = buffer.slice(this.position);
|
|
2523
|
+
var endOfLinePosition = unreadData.indexOf("\n");
|
|
2524
|
+
if (endOfLinePosition !== -1) {
|
|
2525
|
+
this.position += endOfLinePosition + 1;
|
|
2526
|
+
return unreadData.slice(0, endOfLinePosition);
|
|
2527
|
+
} else {
|
|
2528
|
+
return null;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
isBufferTooLong(buffer) {
|
|
2532
|
+
return this.position === buffer.length && buffer.length > MAX_BUFFER_LENGTH;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
var State = /* @__PURE__ */ ((State2) => {
|
|
2536
|
+
State2[State2["CONNECTING"] = 0] = "CONNECTING";
|
|
2537
|
+
State2[State2["OPEN"] = 1] = "OPEN";
|
|
2538
|
+
State2[State2["CLOSED"] = 3] = "CLOSED";
|
|
2539
|
+
return State2;
|
|
2540
|
+
})(State || {});
|
|
2541
|
+
var autoIncrement = 1;
|
|
2542
|
+
class HTTPSocket {
|
|
2543
|
+
constructor(hooks2, url) {
|
|
2544
|
+
this.hooks = hooks2;
|
|
2545
|
+
this.session = randomNumber(1e3) + "/" + randomString(8);
|
|
2546
|
+
this.location = getLocation(url);
|
|
2547
|
+
this.readyState = State.CONNECTING;
|
|
2548
|
+
this.openStream();
|
|
2549
|
+
}
|
|
2550
|
+
send(payload) {
|
|
2551
|
+
return this.sendRaw(JSON.stringify([payload]));
|
|
2552
|
+
}
|
|
2553
|
+
ping() {
|
|
2554
|
+
this.hooks.sendHeartbeat(this);
|
|
2555
|
+
}
|
|
2556
|
+
close(code, reason) {
|
|
2557
|
+
this.onClose(code, reason, true);
|
|
2558
|
+
}
|
|
2559
|
+
/** For internal use only */
|
|
2560
|
+
sendRaw(payload) {
|
|
2561
|
+
if (this.readyState === State.OPEN) {
|
|
2562
|
+
try {
|
|
2563
|
+
NodeJS.createSocketRequest(
|
|
2564
|
+
"POST",
|
|
2565
|
+
getUniqueURL(getSendURL(this.location, this.session))
|
|
2566
|
+
).start(payload);
|
|
2567
|
+
return true;
|
|
2568
|
+
} catch (e) {
|
|
2569
|
+
return false;
|
|
2570
|
+
}
|
|
2571
|
+
} else {
|
|
2572
|
+
return false;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
/** For internal use only */
|
|
2576
|
+
reconnect() {
|
|
2577
|
+
this.closeStream();
|
|
2578
|
+
this.openStream();
|
|
2579
|
+
}
|
|
2580
|
+
/** For internal use only */
|
|
2581
|
+
onClose(code, reason, wasClean) {
|
|
2582
|
+
this.closeStream();
|
|
2583
|
+
this.readyState = State.CLOSED;
|
|
2584
|
+
if (this.onclose) {
|
|
2585
|
+
this.onclose({
|
|
2586
|
+
code,
|
|
2587
|
+
reason,
|
|
2588
|
+
wasClean
|
|
2589
|
+
});
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
onChunk(chunk) {
|
|
2593
|
+
if (chunk.status !== 200) {
|
|
2594
|
+
return;
|
|
2595
|
+
}
|
|
2596
|
+
if (this.readyState === State.OPEN) {
|
|
2597
|
+
this.onActivity();
|
|
2598
|
+
}
|
|
2599
|
+
var payload;
|
|
2600
|
+
var type = chunk.data.slice(0, 1);
|
|
2601
|
+
switch (type) {
|
|
2602
|
+
case "o":
|
|
2603
|
+
payload = JSON.parse(chunk.data.slice(1) || "{}");
|
|
2604
|
+
this.onOpen(payload);
|
|
2605
|
+
break;
|
|
2606
|
+
case "a":
|
|
2607
|
+
payload = JSON.parse(chunk.data.slice(1) || "[]");
|
|
2608
|
+
for (var i = 0; i < payload.length; i++) {
|
|
2609
|
+
this.onEvent(payload[i]);
|
|
2610
|
+
}
|
|
2611
|
+
break;
|
|
2612
|
+
case "m":
|
|
2613
|
+
payload = JSON.parse(chunk.data.slice(1) || "null");
|
|
2614
|
+
this.onEvent(payload);
|
|
2615
|
+
break;
|
|
2616
|
+
case "h":
|
|
2617
|
+
this.hooks.onHeartbeat(this);
|
|
2618
|
+
break;
|
|
2619
|
+
case "c":
|
|
2620
|
+
payload = JSON.parse(chunk.data.slice(1) || "[]");
|
|
2621
|
+
this.onClose(payload[0], payload[1], true);
|
|
2622
|
+
break;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
onOpen(options) {
|
|
2626
|
+
if (this.readyState === State.CONNECTING) {
|
|
2627
|
+
if (options && options.hostname) {
|
|
2628
|
+
this.location.base = replaceHost(this.location.base, options.hostname);
|
|
2629
|
+
}
|
|
2630
|
+
this.readyState = State.OPEN;
|
|
2631
|
+
if (this.onopen) {
|
|
2632
|
+
this.onopen();
|
|
2633
|
+
}
|
|
2634
|
+
} else {
|
|
2635
|
+
this.onClose(1006, "Server lost session", true);
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
onEvent(event) {
|
|
2639
|
+
if (this.readyState === State.OPEN && this.onmessage) {
|
|
2640
|
+
this.onmessage({ data: event });
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
onActivity() {
|
|
2644
|
+
if (this.onactivity) {
|
|
2645
|
+
this.onactivity();
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
onError(error) {
|
|
2649
|
+
if (this.onerror) {
|
|
2650
|
+
this.onerror(error);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
openStream() {
|
|
2654
|
+
this.stream = NodeJS.createSocketRequest(
|
|
2655
|
+
"POST",
|
|
2656
|
+
getUniqueURL(this.hooks.getReceiveURL(this.location, this.session))
|
|
2657
|
+
);
|
|
2658
|
+
this.stream.bind("chunk", (chunk) => {
|
|
2659
|
+
this.onChunk(chunk);
|
|
2660
|
+
});
|
|
2661
|
+
this.stream.bind("finished", (status) => {
|
|
2662
|
+
this.hooks.onFinished(this, status);
|
|
2663
|
+
});
|
|
2664
|
+
this.stream.bind("buffer_too_long", () => {
|
|
2665
|
+
this.reconnect();
|
|
2666
|
+
});
|
|
2667
|
+
try {
|
|
2668
|
+
this.stream.start();
|
|
2669
|
+
} catch (error) {
|
|
2670
|
+
Util.defer(() => {
|
|
2671
|
+
this.onError(error);
|
|
2672
|
+
this.onClose(1006, "Could not start streaming", false);
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
closeStream() {
|
|
2677
|
+
if (this.stream) {
|
|
2678
|
+
this.stream.unbind_all();
|
|
2679
|
+
this.stream.close();
|
|
2680
|
+
this.stream = null;
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
function getLocation(url) {
|
|
2685
|
+
var parts = /([^\?]*)\/*(\??.*)/.exec(url);
|
|
2686
|
+
return {
|
|
2687
|
+
base: parts[1],
|
|
2688
|
+
queryString: parts[2]
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
function getSendURL(url, session) {
|
|
2692
|
+
return url.base + "/" + session + "/xhr_send";
|
|
2693
|
+
}
|
|
2694
|
+
function getUniqueURL(url) {
|
|
2695
|
+
var separator = url.indexOf("?") === -1 ? "?" : "&";
|
|
2696
|
+
return url + separator + "t=" + +/* @__PURE__ */ new Date() + "&n=" + autoIncrement++;
|
|
2697
|
+
}
|
|
2698
|
+
function replaceHost(url, hostname) {
|
|
2699
|
+
var urlParts = /(https?:\/\/)([^\/:]+)((\/|:)?.*)/.exec(url);
|
|
2700
|
+
return urlParts[1] + hostname + urlParts[3];
|
|
2701
|
+
}
|
|
2702
|
+
function randomNumber(max) {
|
|
2703
|
+
return NodeJS.randomInt(max);
|
|
2704
|
+
}
|
|
2705
|
+
function randomString(length) {
|
|
2706
|
+
var result = [];
|
|
2707
|
+
for (var i = 0; i < length; i++) {
|
|
2708
|
+
result.push(randomNumber(32).toString(32));
|
|
2709
|
+
}
|
|
2710
|
+
return result.join("");
|
|
2711
|
+
}
|
|
2712
|
+
var hooks$2 = {
|
|
2713
|
+
getReceiveURL: function(url, session) {
|
|
2714
|
+
return url.base + "/" + session + "/xhr_streaming" + url.queryString;
|
|
2715
|
+
},
|
|
2716
|
+
onHeartbeat: function(socket) {
|
|
2717
|
+
socket.sendRaw("[]");
|
|
2718
|
+
},
|
|
2719
|
+
sendHeartbeat: function(socket) {
|
|
2720
|
+
socket.sendRaw("[]");
|
|
2721
|
+
},
|
|
2722
|
+
onFinished: function(socket, status) {
|
|
2723
|
+
socket.onClose(1006, "Connection interrupted (" + status + ")", false);
|
|
2724
|
+
}
|
|
2725
|
+
};
|
|
2726
|
+
var hooks$1 = {
|
|
2727
|
+
getReceiveURL: function(url, session) {
|
|
2728
|
+
return url.base + "/" + session + "/xhr" + url.queryString;
|
|
2729
|
+
},
|
|
2730
|
+
onHeartbeat: function() {
|
|
2731
|
+
},
|
|
2732
|
+
sendHeartbeat: function(socket) {
|
|
2733
|
+
socket.sendRaw("[]");
|
|
2734
|
+
},
|
|
2735
|
+
onFinished: function(socket, status) {
|
|
2736
|
+
if (status === 200) {
|
|
2737
|
+
socket.reconnect();
|
|
2738
|
+
} else {
|
|
2739
|
+
socket.onClose(1006, "Connection interrupted (" + status + ")", false);
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
};
|
|
2743
|
+
var hooks = {
|
|
2744
|
+
getRequest: function(socket) {
|
|
2745
|
+
var Constructor = NodeJS.getXHRAPI();
|
|
2746
|
+
var xhr2 = new Constructor();
|
|
2747
|
+
xhr2.onreadystatechange = xhr2.onprogress = function() {
|
|
2748
|
+
switch (xhr2.readyState) {
|
|
2749
|
+
case 3:
|
|
2750
|
+
if (xhr2.responseText && xhr2.responseText.length > 0) {
|
|
2751
|
+
socket.onChunk(xhr2.status, xhr2.responseText);
|
|
2752
|
+
}
|
|
2753
|
+
break;
|
|
2754
|
+
case 4:
|
|
2755
|
+
if (xhr2.responseText && xhr2.responseText.length > 0) {
|
|
2756
|
+
socket.onChunk(xhr2.status, xhr2.responseText);
|
|
2757
|
+
}
|
|
2758
|
+
socket.emit("finished", xhr2.status);
|
|
2759
|
+
socket.close();
|
|
2760
|
+
break;
|
|
2761
|
+
}
|
|
2762
|
+
};
|
|
2763
|
+
return xhr2;
|
|
2764
|
+
},
|
|
2765
|
+
abortRequest: function(xhr2) {
|
|
2766
|
+
xhr2.onreadystatechange = null;
|
|
2767
|
+
xhr2.abort();
|
|
2768
|
+
}
|
|
2769
|
+
};
|
|
2770
|
+
var HTTP = {
|
|
2771
|
+
createStreamingSocket(url) {
|
|
2772
|
+
return this.createSocket(hooks$2, url);
|
|
2773
|
+
},
|
|
2774
|
+
createPollingSocket(url) {
|
|
2775
|
+
return this.createSocket(hooks$1, url);
|
|
2776
|
+
},
|
|
2777
|
+
createSocket(hooks2, url) {
|
|
2778
|
+
return new HTTPSocket(hooks2, url);
|
|
2779
|
+
},
|
|
2780
|
+
createXHR(method, url) {
|
|
2781
|
+
return this.createRequest(hooks, method, url);
|
|
2782
|
+
},
|
|
2783
|
+
createRequest(hooks2, method, url) {
|
|
2784
|
+
return new HTTPRequest(hooks2, method, url);
|
|
2785
|
+
}
|
|
2786
|
+
};
|
|
2787
|
+
var Isomorphic = {
|
|
2788
|
+
getDefaultStrategy: getDefaultStrategy$1,
|
|
2789
|
+
Transports: Transports$2,
|
|
2790
|
+
transportConnectionInitializer: transportConnectionInitializer$1,
|
|
2791
|
+
HTTPFactory: HTTP,
|
|
2792
|
+
setup(PusherClass) {
|
|
2793
|
+
PusherClass.ready();
|
|
2794
|
+
},
|
|
2795
|
+
getLocalStorage() {
|
|
2796
|
+
return void 0;
|
|
2797
|
+
},
|
|
2798
|
+
getClientFeatures() {
|
|
2799
|
+
return keys(
|
|
2800
|
+
filterObject({ ws: Transports$2.ws }, function(t) {
|
|
2801
|
+
return t.isSupported({});
|
|
2802
|
+
})
|
|
2803
|
+
);
|
|
2804
|
+
},
|
|
2805
|
+
getProtocol() {
|
|
2806
|
+
return "http:";
|
|
2807
|
+
},
|
|
2808
|
+
isXHRSupported() {
|
|
2809
|
+
return true;
|
|
2810
|
+
},
|
|
2811
|
+
createSocketRequest(method, url) {
|
|
2812
|
+
if (this.isXHRSupported()) {
|
|
2813
|
+
return this.HTTPFactory.createXHR(method, url);
|
|
2814
|
+
} else {
|
|
2815
|
+
throw "Cross-origin HTTP requests are not supported";
|
|
2816
|
+
}
|
|
2817
|
+
},
|
|
2818
|
+
createXHR() {
|
|
2819
|
+
var Constructor = this.getXHRAPI();
|
|
2820
|
+
return new Constructor();
|
|
2821
|
+
},
|
|
2822
|
+
createWebSocket(url) {
|
|
2823
|
+
var Constructor = this.getWebSocketAPI();
|
|
2824
|
+
return new Constructor(url);
|
|
2825
|
+
},
|
|
2826
|
+
addUnloadListener(listener) {
|
|
2827
|
+
},
|
|
2828
|
+
removeUnloadListener(listener) {
|
|
2829
|
+
}
|
|
2830
|
+
};
|
|
2831
|
+
class NetInfo extends Dispatcher {
|
|
2832
|
+
isOnline() {
|
|
2833
|
+
return true;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
var Network = new NetInfo();
|
|
2837
|
+
var AuthRequestType = /* @__PURE__ */ ((AuthRequestType2) => {
|
|
2838
|
+
AuthRequestType2["UserAuthentication"] = "user-authentication";
|
|
2839
|
+
AuthRequestType2["ChannelAuthorization"] = "channel-authorization";
|
|
2840
|
+
return AuthRequestType2;
|
|
2841
|
+
})(AuthRequestType || {});
|
|
2842
|
+
const ajax = function(context, query, authOptions, authRequestType, callback) {
|
|
2843
|
+
const xhr2 = NodeJS.createXHR();
|
|
2844
|
+
xhr2.open("POST", authOptions.endpoint, true);
|
|
2845
|
+
xhr2.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
2846
|
+
for (var headerName in authOptions.headers) {
|
|
2847
|
+
xhr2.setRequestHeader(headerName, authOptions.headers[headerName]);
|
|
2848
|
+
}
|
|
2849
|
+
if (authOptions.headersProvider != null) {
|
|
2850
|
+
let dynamicHeaders = authOptions.headersProvider();
|
|
2851
|
+
for (var headerName in dynamicHeaders) {
|
|
2852
|
+
xhr2.setRequestHeader(headerName, dynamicHeaders[headerName]);
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
xhr2.onreadystatechange = function() {
|
|
2856
|
+
if (xhr2.readyState === 4) {
|
|
2857
|
+
if (xhr2.status === 200) {
|
|
2858
|
+
let data;
|
|
2859
|
+
let parsed = false;
|
|
2860
|
+
try {
|
|
2861
|
+
data = JSON.parse(xhr2.responseText);
|
|
2862
|
+
parsed = true;
|
|
2863
|
+
} catch (e) {
|
|
2864
|
+
callback(
|
|
2865
|
+
new HTTPAuthError(
|
|
2866
|
+
200,
|
|
2867
|
+
`JSON returned from ${authRequestType.toString()} endpoint was invalid, yet status code was 200. Data was: ${xhr2.responseText}`
|
|
2868
|
+
),
|
|
2869
|
+
null
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
if (parsed) {
|
|
2873
|
+
callback(null, data);
|
|
2874
|
+
}
|
|
2875
|
+
} else {
|
|
2876
|
+
let suffix = "";
|
|
2877
|
+
switch (authRequestType) {
|
|
2878
|
+
case AuthRequestType.UserAuthentication:
|
|
2879
|
+
suffix = UrlStore.buildLogSuffix("authenticationEndpoint");
|
|
2880
|
+
break;
|
|
2881
|
+
case AuthRequestType.ChannelAuthorization:
|
|
2882
|
+
suffix = `Clients must be authorized to join private or presence channels. ${UrlStore.buildLogSuffix(
|
|
2883
|
+
"authorizationEndpoint"
|
|
2884
|
+
)}`;
|
|
2885
|
+
break;
|
|
2886
|
+
}
|
|
2887
|
+
callback(
|
|
2888
|
+
new HTTPAuthError(
|
|
2889
|
+
xhr2.status,
|
|
2890
|
+
`Unable to retrieve auth string from ${authRequestType.toString()} endpoint - received status: ${xhr2.status} from ${authOptions.endpoint}. ${suffix}`
|
|
2891
|
+
),
|
|
2892
|
+
null
|
|
2893
|
+
);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2897
|
+
xhr2.send(query);
|
|
2898
|
+
return xhr2;
|
|
2899
|
+
};
|
|
2900
|
+
var getAgent = function(sender, useTLS) {
|
|
2901
|
+
return function(data, callback) {
|
|
2902
|
+
var scheme = "http" + (useTLS ? "s" : "") + "://";
|
|
2903
|
+
var url = scheme + (sender.host || sender.options.host) + sender.options.path;
|
|
2904
|
+
var query = buildQueryString(data);
|
|
2905
|
+
url += "/2?" + query;
|
|
2906
|
+
var xhr2 = NodeJS.createXHR();
|
|
2907
|
+
xhr2.open("GET", url, true);
|
|
2908
|
+
xhr2.onreadystatechange = function() {
|
|
2909
|
+
if (xhr2.readyState === 4) {
|
|
2910
|
+
let { status, responseText } = xhr2;
|
|
2911
|
+
if (status !== 200) {
|
|
2912
|
+
Logger$1.debug(
|
|
2913
|
+
`TimelineSender Error: received ${status} from stats.pusher.com`
|
|
2914
|
+
);
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
try {
|
|
2918
|
+
var { host } = JSON.parse(responseText);
|
|
2919
|
+
} catch (e) {
|
|
2920
|
+
Logger$1.debug(`TimelineSenderError: invalid response ${responseText}`);
|
|
2921
|
+
}
|
|
2922
|
+
if (host) {
|
|
2923
|
+
sender.host = host;
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
};
|
|
2927
|
+
xhr2.send();
|
|
2928
|
+
};
|
|
2929
|
+
};
|
|
2930
|
+
var xhr = {
|
|
2931
|
+
name: "xhr",
|
|
2932
|
+
getAgent
|
|
2933
|
+
};
|
|
2934
|
+
const {
|
|
2935
|
+
getDefaultStrategy,
|
|
2936
|
+
Transports: Transports$1,
|
|
2937
|
+
setup,
|
|
2938
|
+
getProtocol,
|
|
2939
|
+
isXHRSupported,
|
|
2940
|
+
getLocalStorage,
|
|
2941
|
+
createXHR,
|
|
2942
|
+
createWebSocket,
|
|
2943
|
+
addUnloadListener,
|
|
2944
|
+
removeUnloadListener,
|
|
2945
|
+
transportConnectionInitializer,
|
|
2946
|
+
createSocketRequest,
|
|
2947
|
+
HTTPFactory
|
|
2948
|
+
} = Isomorphic;
|
|
2949
|
+
const NodeJS = {
|
|
2950
|
+
getDefaultStrategy,
|
|
2951
|
+
Transports: Transports$1,
|
|
2952
|
+
setup,
|
|
2953
|
+
getProtocol,
|
|
2954
|
+
isXHRSupported,
|
|
2955
|
+
createSocketRequest,
|
|
2956
|
+
getLocalStorage,
|
|
2957
|
+
createXHR,
|
|
2958
|
+
createWebSocket,
|
|
2959
|
+
addUnloadListener,
|
|
2960
|
+
removeUnloadListener,
|
|
2961
|
+
transportConnectionInitializer,
|
|
2962
|
+
HTTPFactory,
|
|
2963
|
+
TimelineTransport: xhr,
|
|
2964
|
+
getAuthorizers() {
|
|
2965
|
+
return { ajax };
|
|
2966
|
+
},
|
|
2967
|
+
getWebSocketAPI() {
|
|
2968
|
+
return fayeWebsocket.Client;
|
|
2969
|
+
},
|
|
2970
|
+
getXHRAPI() {
|
|
2971
|
+
return xmlhttprequest.XMLHttpRequest;
|
|
2972
|
+
},
|
|
2973
|
+
getNetwork() {
|
|
2974
|
+
return Network;
|
|
2975
|
+
},
|
|
2976
|
+
randomInt(max) {
|
|
2977
|
+
return crypto.randomInt(max);
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
var TimelineLevel = /* @__PURE__ */ ((TimelineLevel2) => {
|
|
2981
|
+
TimelineLevel2[TimelineLevel2["ERROR"] = 3] = "ERROR";
|
|
2982
|
+
TimelineLevel2[TimelineLevel2["INFO"] = 6] = "INFO";
|
|
2983
|
+
TimelineLevel2[TimelineLevel2["DEBUG"] = 7] = "DEBUG";
|
|
2984
|
+
return TimelineLevel2;
|
|
2985
|
+
})(TimelineLevel || {});
|
|
2986
|
+
class Timeline {
|
|
2987
|
+
constructor(key, session, options) {
|
|
2988
|
+
this.key = key;
|
|
2989
|
+
this.session = session;
|
|
2990
|
+
this.events = [];
|
|
2991
|
+
this.options = options || {};
|
|
2992
|
+
this.sent = 0;
|
|
2993
|
+
this.uniqueID = 0;
|
|
2994
|
+
}
|
|
2995
|
+
log(level, event) {
|
|
2996
|
+
if (level <= this.options.level) {
|
|
2997
|
+
this.events.push(
|
|
2998
|
+
extend({}, event, { timestamp: Util.now() })
|
|
2999
|
+
);
|
|
3000
|
+
if (this.options.limit && this.events.length > this.options.limit) {
|
|
3001
|
+
this.events.shift();
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
error(event) {
|
|
3006
|
+
this.log(TimelineLevel.ERROR, event);
|
|
3007
|
+
}
|
|
3008
|
+
info(event) {
|
|
3009
|
+
this.log(TimelineLevel.INFO, event);
|
|
3010
|
+
}
|
|
3011
|
+
debug(event) {
|
|
3012
|
+
this.log(TimelineLevel.DEBUG, event);
|
|
3013
|
+
}
|
|
3014
|
+
isEmpty() {
|
|
3015
|
+
return this.events.length === 0;
|
|
3016
|
+
}
|
|
3017
|
+
send(sendfn, callback) {
|
|
3018
|
+
var data = extend(
|
|
3019
|
+
{
|
|
3020
|
+
session: this.session,
|
|
3021
|
+
bundle: this.sent + 1,
|
|
3022
|
+
key: this.key,
|
|
3023
|
+
lib: "js",
|
|
3024
|
+
version: this.options.version,
|
|
3025
|
+
cluster: this.options.cluster,
|
|
3026
|
+
features: this.options.features,
|
|
3027
|
+
timeline: this.events
|
|
3028
|
+
},
|
|
3029
|
+
this.options.params
|
|
3030
|
+
);
|
|
3031
|
+
this.events = [];
|
|
3032
|
+
sendfn(data, (error, result) => {
|
|
3033
|
+
if (!error) {
|
|
3034
|
+
this.sent++;
|
|
3035
|
+
}
|
|
3036
|
+
if (callback) {
|
|
3037
|
+
callback(error, result);
|
|
3038
|
+
}
|
|
3039
|
+
});
|
|
3040
|
+
return true;
|
|
3041
|
+
}
|
|
3042
|
+
generateUniqueID() {
|
|
3043
|
+
this.uniqueID++;
|
|
3044
|
+
return this.uniqueID;
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
class TransportStrategy {
|
|
3048
|
+
constructor(name, priority, transport, options) {
|
|
3049
|
+
this.name = name;
|
|
3050
|
+
this.priority = priority;
|
|
3051
|
+
this.transport = transport;
|
|
3052
|
+
this.options = options || {};
|
|
3053
|
+
}
|
|
3054
|
+
/** Returns whether the transport is supported in the browser.
|
|
3055
|
+
*
|
|
3056
|
+
* @returns {Boolean}
|
|
3057
|
+
*/
|
|
3058
|
+
isSupported() {
|
|
3059
|
+
return this.transport.isSupported({
|
|
3060
|
+
useTLS: this.options.useTLS
|
|
3061
|
+
});
|
|
3062
|
+
}
|
|
3063
|
+
/** Launches a connection attempt and returns a strategy runner.
|
|
3064
|
+
*
|
|
3065
|
+
* @param {Function} callback
|
|
3066
|
+
* @return {Object} strategy runner
|
|
3067
|
+
*/
|
|
3068
|
+
connect(minPriority, callback) {
|
|
3069
|
+
if (!this.isSupported()) {
|
|
3070
|
+
return failAttempt(new UnsupportedStrategy$1(), callback);
|
|
3071
|
+
} else if (this.priority < minPriority) {
|
|
3072
|
+
return failAttempt(new TransportPriorityTooLow(), callback);
|
|
3073
|
+
}
|
|
3074
|
+
var connected = false;
|
|
3075
|
+
var transport = this.transport.createConnection(
|
|
3076
|
+
this.name,
|
|
3077
|
+
this.priority,
|
|
3078
|
+
this.options.key,
|
|
3079
|
+
this.options
|
|
3080
|
+
);
|
|
3081
|
+
var handshake = null;
|
|
3082
|
+
var onInitialized = function() {
|
|
3083
|
+
transport.unbind("initialized", onInitialized);
|
|
3084
|
+
transport.connect();
|
|
3085
|
+
};
|
|
3086
|
+
var onOpen = function() {
|
|
3087
|
+
handshake = Factory.createHandshake(transport, function(result) {
|
|
3088
|
+
connected = true;
|
|
3089
|
+
unbindListeners();
|
|
3090
|
+
callback(null, result);
|
|
3091
|
+
});
|
|
3092
|
+
};
|
|
3093
|
+
var onError = function(error) {
|
|
3094
|
+
unbindListeners();
|
|
3095
|
+
callback(error);
|
|
3096
|
+
};
|
|
3097
|
+
var onClosed = function() {
|
|
3098
|
+
unbindListeners();
|
|
3099
|
+
var serializedTransport;
|
|
3100
|
+
serializedTransport = safeJSONStringify(transport);
|
|
3101
|
+
callback(new TransportClosed(serializedTransport));
|
|
3102
|
+
};
|
|
3103
|
+
var unbindListeners = function() {
|
|
3104
|
+
transport.unbind("initialized", onInitialized);
|
|
3105
|
+
transport.unbind("open", onOpen);
|
|
3106
|
+
transport.unbind("error", onError);
|
|
3107
|
+
transport.unbind("closed", onClosed);
|
|
3108
|
+
};
|
|
3109
|
+
transport.bind("initialized", onInitialized);
|
|
3110
|
+
transport.bind("open", onOpen);
|
|
3111
|
+
transport.bind("error", onError);
|
|
3112
|
+
transport.bind("closed", onClosed);
|
|
3113
|
+
transport.initialize();
|
|
3114
|
+
return {
|
|
3115
|
+
abort: () => {
|
|
3116
|
+
if (connected) {
|
|
3117
|
+
return;
|
|
3118
|
+
}
|
|
3119
|
+
unbindListeners();
|
|
3120
|
+
if (handshake) {
|
|
3121
|
+
handshake.close();
|
|
3122
|
+
} else {
|
|
3123
|
+
transport.close();
|
|
3124
|
+
}
|
|
3125
|
+
},
|
|
3126
|
+
forceMinPriority: (p) => {
|
|
3127
|
+
if (connected) {
|
|
3128
|
+
return;
|
|
3129
|
+
}
|
|
3130
|
+
if (this.priority < p) {
|
|
3131
|
+
if (handshake) {
|
|
3132
|
+
handshake.close();
|
|
3133
|
+
} else {
|
|
3134
|
+
transport.close();
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
function failAttempt(error, callback) {
|
|
3142
|
+
Util.defer(function() {
|
|
3143
|
+
callback(error);
|
|
3144
|
+
});
|
|
3145
|
+
return {
|
|
3146
|
+
abort: function() {
|
|
3147
|
+
},
|
|
3148
|
+
forceMinPriority: function() {
|
|
3149
|
+
}
|
|
3150
|
+
};
|
|
3151
|
+
}
|
|
3152
|
+
const { Transports } = NodeJS;
|
|
3153
|
+
var defineTransport = function(config2, name, type, priority, options, manager) {
|
|
3154
|
+
var transportClass = Transports[type];
|
|
3155
|
+
if (!transportClass) {
|
|
3156
|
+
throw new UnsupportedTransport(type);
|
|
3157
|
+
}
|
|
3158
|
+
var enabled = (!config2.enabledTransports || arrayIndexOf(config2.enabledTransports, name) !== -1) && (!config2.disabledTransports || arrayIndexOf(config2.disabledTransports, name) === -1);
|
|
3159
|
+
var transport;
|
|
3160
|
+
if (enabled) {
|
|
3161
|
+
options = Object.assign(
|
|
3162
|
+
{ ignoreNullOrigin: config2.ignoreNullOrigin },
|
|
3163
|
+
options
|
|
3164
|
+
);
|
|
3165
|
+
transport = new TransportStrategy(
|
|
3166
|
+
name,
|
|
3167
|
+
priority,
|
|
3168
|
+
manager ? manager.getAssistant(transportClass) : transportClass,
|
|
3169
|
+
options
|
|
3170
|
+
);
|
|
3171
|
+
} else {
|
|
3172
|
+
transport = UnsupportedStrategy2;
|
|
3173
|
+
}
|
|
3174
|
+
return transport;
|
|
3175
|
+
};
|
|
3176
|
+
var UnsupportedStrategy2 = {
|
|
3177
|
+
isSupported: function() {
|
|
3178
|
+
return false;
|
|
3179
|
+
},
|
|
3180
|
+
connect: function(_, callback) {
|
|
3181
|
+
var deferred = Util.defer(function() {
|
|
3182
|
+
callback(new UnsupportedStrategy$1());
|
|
3183
|
+
});
|
|
3184
|
+
return {
|
|
3185
|
+
abort: function() {
|
|
3186
|
+
deferred.ensureAborted();
|
|
3187
|
+
},
|
|
3188
|
+
forceMinPriority: function() {
|
|
3189
|
+
}
|
|
3190
|
+
};
|
|
3191
|
+
}
|
|
3192
|
+
};
|
|
3193
|
+
function validateOptions(options) {
|
|
3194
|
+
if (options == null) {
|
|
3195
|
+
throw "You must pass an options object";
|
|
3196
|
+
}
|
|
3197
|
+
if (options.cluster == null) {
|
|
3198
|
+
throw "Options object must provide a cluster";
|
|
3199
|
+
}
|
|
3200
|
+
if ("disableStats" in options) {
|
|
3201
|
+
Logger$1.warn(
|
|
3202
|
+
"The disableStats option is deprecated in favor of enableStats"
|
|
3203
|
+
);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
const composeChannelQuery$1 = (params, authOptions) => {
|
|
3207
|
+
var query = "socket_id=" + encodeURIComponent(params.socketId);
|
|
3208
|
+
for (var key in authOptions.params) {
|
|
3209
|
+
query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(authOptions.params[key]);
|
|
3210
|
+
}
|
|
3211
|
+
if (authOptions.paramsProvider != null) {
|
|
3212
|
+
let dynamicParams = authOptions.paramsProvider();
|
|
3213
|
+
for (var key in dynamicParams) {
|
|
3214
|
+
query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(dynamicParams[key]);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
return query;
|
|
3218
|
+
};
|
|
3219
|
+
const UserAuthenticator = (authOptions) => {
|
|
3220
|
+
if (typeof NodeJS.getAuthorizers()[authOptions.transport] === "undefined") {
|
|
3221
|
+
throw `'${authOptions.transport}' is not a recognized auth transport`;
|
|
3222
|
+
}
|
|
3223
|
+
return (params, callback) => {
|
|
3224
|
+
const query = composeChannelQuery$1(params, authOptions);
|
|
3225
|
+
NodeJS.getAuthorizers()[authOptions.transport](
|
|
3226
|
+
NodeJS,
|
|
3227
|
+
query,
|
|
3228
|
+
authOptions,
|
|
3229
|
+
AuthRequestType.UserAuthentication,
|
|
3230
|
+
callback
|
|
3231
|
+
);
|
|
3232
|
+
};
|
|
3233
|
+
};
|
|
3234
|
+
const composeChannelQuery = (params, authOptions) => {
|
|
3235
|
+
var query = "socket_id=" + encodeURIComponent(params.socketId);
|
|
3236
|
+
query += "&channel_name=" + encodeURIComponent(params.channelName);
|
|
3237
|
+
for (var key in authOptions.params) {
|
|
3238
|
+
query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(authOptions.params[key]);
|
|
3239
|
+
}
|
|
3240
|
+
if (authOptions.paramsProvider != null) {
|
|
3241
|
+
let dynamicParams = authOptions.paramsProvider();
|
|
3242
|
+
for (var key in dynamicParams) {
|
|
3243
|
+
query += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(dynamicParams[key]);
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
return query;
|
|
3247
|
+
};
|
|
3248
|
+
const ChannelAuthorizer = (authOptions) => {
|
|
3249
|
+
if (typeof NodeJS.getAuthorizers()[authOptions.transport] === "undefined") {
|
|
3250
|
+
throw `'${authOptions.transport}' is not a recognized auth transport`;
|
|
3251
|
+
}
|
|
3252
|
+
return (params, callback) => {
|
|
3253
|
+
const query = composeChannelQuery(params, authOptions);
|
|
3254
|
+
NodeJS.getAuthorizers()[authOptions.transport](
|
|
3255
|
+
NodeJS,
|
|
3256
|
+
query,
|
|
3257
|
+
authOptions,
|
|
3258
|
+
AuthRequestType.ChannelAuthorization,
|
|
3259
|
+
callback
|
|
3260
|
+
);
|
|
3261
|
+
};
|
|
3262
|
+
};
|
|
3263
|
+
const ChannelAuthorizerProxy = (pusher, authOptions, channelAuthorizerGenerator) => {
|
|
3264
|
+
const deprecatedAuthorizerOptions = {
|
|
3265
|
+
authTransport: authOptions.transport,
|
|
3266
|
+
authEndpoint: authOptions.endpoint,
|
|
3267
|
+
auth: {
|
|
3268
|
+
params: authOptions.params,
|
|
3269
|
+
headers: authOptions.headers
|
|
3270
|
+
}
|
|
3271
|
+
};
|
|
3272
|
+
return (params, callback) => {
|
|
3273
|
+
const channel = pusher.channel(params.channelName);
|
|
3274
|
+
const channelAuthorizer = channelAuthorizerGenerator(channel, deprecatedAuthorizerOptions);
|
|
3275
|
+
channelAuthorizer.authorize(params.socketId, callback);
|
|
3276
|
+
};
|
|
3277
|
+
};
|
|
3278
|
+
function getConfig(opts, pusher) {
|
|
3279
|
+
let config2 = {
|
|
3280
|
+
activityTimeout: opts.activityTimeout || Defaults.activityTimeout,
|
|
3281
|
+
cluster: opts.cluster,
|
|
3282
|
+
httpPath: opts.httpPath || Defaults.httpPath,
|
|
3283
|
+
httpPort: opts.httpPort || Defaults.httpPort,
|
|
3284
|
+
httpsPort: opts.httpsPort || Defaults.httpsPort,
|
|
3285
|
+
pongTimeout: opts.pongTimeout || Defaults.pongTimeout,
|
|
3286
|
+
statsHost: opts.statsHost || Defaults.stats_host,
|
|
3287
|
+
unavailableTimeout: opts.unavailableTimeout || Defaults.unavailableTimeout,
|
|
3288
|
+
wsPath: opts.wsPath || Defaults.wsPath,
|
|
3289
|
+
wsPort: opts.wsPort || Defaults.wsPort,
|
|
3290
|
+
wssPort: opts.wssPort || Defaults.wssPort,
|
|
3291
|
+
enableStats: getEnableStatsConfig(opts),
|
|
3292
|
+
httpHost: getHttpHost(opts),
|
|
3293
|
+
useTLS: shouldUseTLS(opts),
|
|
3294
|
+
wsHost: getWebsocketHost(opts),
|
|
3295
|
+
userAuthenticator: buildUserAuthenticator(opts),
|
|
3296
|
+
channelAuthorizer: buildChannelAuthorizer(opts, pusher)
|
|
3297
|
+
};
|
|
3298
|
+
if ("disabledTransports" in opts)
|
|
3299
|
+
config2.disabledTransports = opts.disabledTransports;
|
|
3300
|
+
if ("enabledTransports" in opts)
|
|
3301
|
+
config2.enabledTransports = opts.enabledTransports;
|
|
3302
|
+
if ("ignoreNullOrigin" in opts)
|
|
3303
|
+
config2.ignoreNullOrigin = opts.ignoreNullOrigin;
|
|
3304
|
+
if ("timelineParams" in opts) config2.timelineParams = opts.timelineParams;
|
|
3305
|
+
if ("nacl" in opts) {
|
|
3306
|
+
config2.nacl = opts.nacl;
|
|
3307
|
+
}
|
|
3308
|
+
return config2;
|
|
3309
|
+
}
|
|
3310
|
+
function getHttpHost(opts) {
|
|
3311
|
+
if (opts.httpHost) {
|
|
3312
|
+
return opts.httpHost;
|
|
3313
|
+
}
|
|
3314
|
+
if (opts.cluster) {
|
|
3315
|
+
return `sockjs-${opts.cluster}.pusher.com`;
|
|
3316
|
+
}
|
|
3317
|
+
return Defaults.httpHost;
|
|
3318
|
+
}
|
|
3319
|
+
function getWebsocketHost(opts) {
|
|
3320
|
+
if (opts.wsHost) {
|
|
3321
|
+
return opts.wsHost;
|
|
3322
|
+
}
|
|
3323
|
+
return getWebsocketHostFromCluster(opts.cluster);
|
|
3324
|
+
}
|
|
3325
|
+
function getWebsocketHostFromCluster(cluster) {
|
|
3326
|
+
return `ws-${cluster}.pusher.com`;
|
|
3327
|
+
}
|
|
3328
|
+
function shouldUseTLS(opts) {
|
|
3329
|
+
if (NodeJS.getProtocol() === "https:") {
|
|
3330
|
+
return true;
|
|
3331
|
+
} else if (opts.forceTLS === false) {
|
|
3332
|
+
return false;
|
|
3333
|
+
}
|
|
3334
|
+
return true;
|
|
3335
|
+
}
|
|
3336
|
+
function getEnableStatsConfig(opts) {
|
|
3337
|
+
if ("enableStats" in opts) {
|
|
3338
|
+
return opts.enableStats;
|
|
3339
|
+
}
|
|
3340
|
+
if ("disableStats" in opts) {
|
|
3341
|
+
return !opts.disableStats;
|
|
3342
|
+
}
|
|
3343
|
+
return false;
|
|
3344
|
+
}
|
|
3345
|
+
function buildUserAuthenticator(opts) {
|
|
3346
|
+
const userAuthentication = {
|
|
3347
|
+
...Defaults.userAuthentication,
|
|
3348
|
+
...opts.userAuthentication
|
|
3349
|
+
};
|
|
3350
|
+
if ("customHandler" in userAuthentication && userAuthentication["customHandler"] != null) {
|
|
3351
|
+
return userAuthentication["customHandler"];
|
|
3352
|
+
}
|
|
3353
|
+
return UserAuthenticator(userAuthentication);
|
|
3354
|
+
}
|
|
3355
|
+
function buildChannelAuth(opts, pusher) {
|
|
3356
|
+
let channelAuthorization;
|
|
3357
|
+
if ("channelAuthorization" in opts) {
|
|
3358
|
+
channelAuthorization = {
|
|
3359
|
+
...Defaults.channelAuthorization,
|
|
3360
|
+
...opts.channelAuthorization
|
|
3361
|
+
};
|
|
3362
|
+
} else {
|
|
3363
|
+
channelAuthorization = {
|
|
3364
|
+
transport: opts.authTransport || Defaults.authTransport,
|
|
3365
|
+
endpoint: opts.authEndpoint || Defaults.authEndpoint
|
|
3366
|
+
};
|
|
3367
|
+
if ("auth" in opts) {
|
|
3368
|
+
if ("params" in opts.auth) channelAuthorization.params = opts.auth.params;
|
|
3369
|
+
if ("headers" in opts.auth)
|
|
3370
|
+
channelAuthorization.headers = opts.auth.headers;
|
|
3371
|
+
}
|
|
3372
|
+
if ("authorizer" in opts)
|
|
3373
|
+
channelAuthorization.customHandler = ChannelAuthorizerProxy(
|
|
3374
|
+
pusher,
|
|
3375
|
+
channelAuthorization,
|
|
3376
|
+
opts.authorizer
|
|
3377
|
+
);
|
|
3378
|
+
}
|
|
3379
|
+
return channelAuthorization;
|
|
3380
|
+
}
|
|
3381
|
+
function buildChannelAuthorizer(opts, pusher) {
|
|
3382
|
+
const channelAuthorization = buildChannelAuth(opts, pusher);
|
|
3383
|
+
if ("customHandler" in channelAuthorization && channelAuthorization["customHandler"] != null) {
|
|
3384
|
+
return channelAuthorization["customHandler"];
|
|
3385
|
+
}
|
|
3386
|
+
return ChannelAuthorizer(channelAuthorization);
|
|
3387
|
+
}
|
|
3388
|
+
class WatchlistFacade extends Dispatcher {
|
|
3389
|
+
constructor(pusher) {
|
|
3390
|
+
super(function(eventName, data) {
|
|
3391
|
+
Logger$1.debug(`No callbacks on watchlist events for ${eventName}`);
|
|
3392
|
+
});
|
|
3393
|
+
this.pusher = pusher;
|
|
3394
|
+
this.bindWatchlistInternalEvent();
|
|
3395
|
+
}
|
|
3396
|
+
handleEvent(pusherEvent) {
|
|
3397
|
+
pusherEvent.data.events.forEach((watchlistEvent) => {
|
|
3398
|
+
this.emit(watchlistEvent.name, watchlistEvent);
|
|
3399
|
+
});
|
|
3400
|
+
}
|
|
3401
|
+
bindWatchlistInternalEvent() {
|
|
3402
|
+
this.pusher.connection.bind("message", (pusherEvent) => {
|
|
3403
|
+
var eventName = pusherEvent.event;
|
|
3404
|
+
if (eventName === "pusher_internal:watchlist_events") {
|
|
3405
|
+
this.handleEvent(pusherEvent);
|
|
3406
|
+
}
|
|
3407
|
+
});
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
function flatPromise() {
|
|
3411
|
+
let resolve, reject;
|
|
3412
|
+
const promise = new Promise((res, rej) => {
|
|
3413
|
+
resolve = res;
|
|
3414
|
+
reject = rej;
|
|
3415
|
+
});
|
|
3416
|
+
return { promise, resolve, reject };
|
|
3417
|
+
}
|
|
3418
|
+
class UserFacade extends Dispatcher {
|
|
3419
|
+
constructor(pusher) {
|
|
3420
|
+
super(function(eventName, data) {
|
|
3421
|
+
Logger$1.debug("No callbacks on user for " + eventName);
|
|
3422
|
+
});
|
|
3423
|
+
this.signin_requested = false;
|
|
3424
|
+
this.user_data = null;
|
|
3425
|
+
this.serverToUserChannel = null;
|
|
3426
|
+
this.signinDonePromise = null;
|
|
3427
|
+
this._signinDoneResolve = null;
|
|
3428
|
+
this._onAuthorize = (err, authData) => {
|
|
3429
|
+
if (err) {
|
|
3430
|
+
Logger$1.warn(`Error during signin: ${err}`);
|
|
3431
|
+
this._cleanup();
|
|
3432
|
+
return;
|
|
3433
|
+
}
|
|
3434
|
+
this.pusher.send_event("pusher:signin", {
|
|
3435
|
+
auth: authData.auth,
|
|
3436
|
+
user_data: authData.user_data
|
|
3437
|
+
});
|
|
3438
|
+
};
|
|
3439
|
+
this.pusher = pusher;
|
|
3440
|
+
this.pusher.connection.bind("state_change", ({ previous, current }) => {
|
|
3441
|
+
if (previous !== "connected" && current === "connected") {
|
|
3442
|
+
this._signin();
|
|
3443
|
+
}
|
|
3444
|
+
if (previous === "connected" && current !== "connected") {
|
|
3445
|
+
this._cleanup();
|
|
3446
|
+
this._newSigninPromiseIfNeeded();
|
|
3447
|
+
}
|
|
3448
|
+
});
|
|
3449
|
+
this.watchlist = new WatchlistFacade(pusher);
|
|
3450
|
+
this.pusher.connection.bind("message", (event) => {
|
|
3451
|
+
var eventName = event.event;
|
|
3452
|
+
if (eventName === "pusher:signin_success") {
|
|
3453
|
+
this._onSigninSuccess(event.data);
|
|
3454
|
+
}
|
|
3455
|
+
if (this.serverToUserChannel && this.serverToUserChannel.name === event.channel) {
|
|
3456
|
+
this.serverToUserChannel.handleEvent(event);
|
|
3457
|
+
}
|
|
3458
|
+
});
|
|
3459
|
+
}
|
|
3460
|
+
signin() {
|
|
3461
|
+
if (this.signin_requested) {
|
|
3462
|
+
return;
|
|
3463
|
+
}
|
|
3464
|
+
this.signin_requested = true;
|
|
3465
|
+
this._signin();
|
|
3466
|
+
}
|
|
3467
|
+
_signin() {
|
|
3468
|
+
if (!this.signin_requested) {
|
|
3469
|
+
return;
|
|
3470
|
+
}
|
|
3471
|
+
this._newSigninPromiseIfNeeded();
|
|
3472
|
+
if (this.pusher.connection.state !== "connected") {
|
|
3473
|
+
return;
|
|
3474
|
+
}
|
|
3475
|
+
this.pusher.config.userAuthenticator(
|
|
3476
|
+
{
|
|
3477
|
+
socketId: this.pusher.connection.socket_id
|
|
3478
|
+
},
|
|
3479
|
+
this._onAuthorize
|
|
3480
|
+
);
|
|
3481
|
+
}
|
|
3482
|
+
_onSigninSuccess(data) {
|
|
3483
|
+
try {
|
|
3484
|
+
this.user_data = JSON.parse(data.user_data);
|
|
3485
|
+
} catch (e) {
|
|
3486
|
+
Logger$1.error(`Failed parsing user data after signin: ${data.user_data}`);
|
|
3487
|
+
this._cleanup();
|
|
3488
|
+
return;
|
|
3489
|
+
}
|
|
3490
|
+
if (typeof this.user_data.id !== "string" || this.user_data.id === "") {
|
|
3491
|
+
Logger$1.error(
|
|
3492
|
+
`user_data doesn't contain an id. user_data: ${this.user_data}`
|
|
3493
|
+
);
|
|
3494
|
+
this._cleanup();
|
|
3495
|
+
return;
|
|
3496
|
+
}
|
|
3497
|
+
this._signinDoneResolve();
|
|
3498
|
+
this._subscribeChannels();
|
|
3499
|
+
}
|
|
3500
|
+
_subscribeChannels() {
|
|
3501
|
+
const ensure_subscribed = (channel) => {
|
|
3502
|
+
if (channel.subscriptionPending && channel.subscriptionCancelled) {
|
|
3503
|
+
channel.reinstateSubscription();
|
|
3504
|
+
} else if (!channel.subscriptionPending && this.pusher.connection.state === "connected") {
|
|
3505
|
+
channel.subscribe();
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
this.serverToUserChannel = new Channel(
|
|
3509
|
+
`#server-to-user-${this.user_data.id}`,
|
|
3510
|
+
this.pusher
|
|
3511
|
+
);
|
|
3512
|
+
this.serverToUserChannel.bind_global((eventName, data) => {
|
|
3513
|
+
if (eventName.indexOf("pusher_internal:") === 0 || eventName.indexOf("pusher:") === 0) {
|
|
3514
|
+
return;
|
|
3515
|
+
}
|
|
3516
|
+
this.emit(eventName, data);
|
|
3517
|
+
});
|
|
3518
|
+
ensure_subscribed(this.serverToUserChannel);
|
|
3519
|
+
}
|
|
3520
|
+
_cleanup() {
|
|
3521
|
+
this.user_data = null;
|
|
3522
|
+
if (this.serverToUserChannel) {
|
|
3523
|
+
this.serverToUserChannel.unbind_all();
|
|
3524
|
+
this.serverToUserChannel.disconnect();
|
|
3525
|
+
this.serverToUserChannel = null;
|
|
3526
|
+
}
|
|
3527
|
+
if (this.signin_requested) {
|
|
3528
|
+
this._signinDoneResolve();
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
_newSigninPromiseIfNeeded() {
|
|
3532
|
+
if (!this.signin_requested) {
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3535
|
+
if (this.signinDonePromise && !this.signinDonePromise.done) {
|
|
3536
|
+
return;
|
|
3537
|
+
}
|
|
3538
|
+
const { promise, resolve } = flatPromise();
|
|
3539
|
+
promise.done = false;
|
|
3540
|
+
const setDone = () => {
|
|
3541
|
+
promise.done = true;
|
|
3542
|
+
};
|
|
3543
|
+
promise.then(setDone).catch(setDone);
|
|
3544
|
+
this.signinDonePromise = promise;
|
|
3545
|
+
this._signinDoneResolve = resolve;
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
class ChannelState {
|
|
3549
|
+
constructor(channelName) {
|
|
3550
|
+
this.channelName = channelName;
|
|
3551
|
+
this.conflationKey = null;
|
|
3552
|
+
this.maxMessagesPerKey = 10;
|
|
3553
|
+
this.conflationCaches = /* @__PURE__ */ new Map();
|
|
3554
|
+
this.baseMessage = null;
|
|
3555
|
+
this.baseSequence = null;
|
|
3556
|
+
this.lastSequence = null;
|
|
3557
|
+
this.deltaCount = 0;
|
|
3558
|
+
this.fullMessageCount = 0;
|
|
3559
|
+
}
|
|
3560
|
+
/**
|
|
3561
|
+
* Initialize cache from server sync
|
|
3562
|
+
*/
|
|
3563
|
+
initializeFromCacheSync(data) {
|
|
3564
|
+
this.conflationKey = data.conflation_key || null;
|
|
3565
|
+
this.maxMessagesPerKey = data.max_messages_per_key || 10;
|
|
3566
|
+
this.conflationCaches.clear();
|
|
3567
|
+
if (data.states) {
|
|
3568
|
+
for (const [key, messages] of Object.entries(data.states)) {
|
|
3569
|
+
const cache = messages.map((msg) => ({
|
|
3570
|
+
content: msg.content,
|
|
3571
|
+
sequence: msg.seq
|
|
3572
|
+
}));
|
|
3573
|
+
this.conflationCaches.set(key, cache);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
/**
|
|
3578
|
+
* Set new base message (legacy - for non-conflation channels)
|
|
3579
|
+
*/
|
|
3580
|
+
setBase(message, sequence) {
|
|
3581
|
+
this.baseMessage = message;
|
|
3582
|
+
this.baseSequence = sequence;
|
|
3583
|
+
this.lastSequence = sequence;
|
|
3584
|
+
}
|
|
3585
|
+
/**
|
|
3586
|
+
* Get base message for a conflation key at specific index
|
|
3587
|
+
* Note: baseIndex is the sequence number, not array index
|
|
3588
|
+
*/
|
|
3589
|
+
getBaseMessage(conflationKeyValue, baseIndex) {
|
|
3590
|
+
if (!this.conflationKey) {
|
|
3591
|
+
return this.baseMessage;
|
|
3592
|
+
}
|
|
3593
|
+
const key = conflationKeyValue || "";
|
|
3594
|
+
const cache = this.conflationCaches.get(key);
|
|
3595
|
+
if (!cache || baseIndex === void 0) {
|
|
3596
|
+
console.error("[ChannelState] No cache or baseIndex undefined", {
|
|
3597
|
+
hasCache: !!cache,
|
|
3598
|
+
baseIndex,
|
|
3599
|
+
key,
|
|
3600
|
+
allCacheKeys: Array.from(this.conflationCaches.keys())
|
|
3601
|
+
});
|
|
3602
|
+
return null;
|
|
3603
|
+
}
|
|
3604
|
+
const message = cache.find((msg) => msg.sequence === baseIndex);
|
|
3605
|
+
if (!message) {
|
|
3606
|
+
console.error("[ChannelState] Could not find message with sequence", {
|
|
3607
|
+
searchingFor: baseIndex,
|
|
3608
|
+
cacheSize: cache.length,
|
|
3609
|
+
cacheSequences: cache.map((m) => m.sequence),
|
|
3610
|
+
key: conflationKeyValue
|
|
3611
|
+
});
|
|
3612
|
+
return null;
|
|
3613
|
+
}
|
|
3614
|
+
return message.content;
|
|
3615
|
+
}
|
|
3616
|
+
/**
|
|
3617
|
+
* Add or update message in conflation cache
|
|
3618
|
+
*/
|
|
3619
|
+
updateConflationCache(conflationKeyValue, message, sequence) {
|
|
3620
|
+
const key = conflationKeyValue || "";
|
|
3621
|
+
let cache = this.conflationCaches.get(key);
|
|
3622
|
+
if (!cache) {
|
|
3623
|
+
cache = [];
|
|
3624
|
+
this.conflationCaches.set(key, cache);
|
|
3625
|
+
}
|
|
3626
|
+
if (cache.length > 0) {
|
|
3627
|
+
const lastCacheItem = cache[cache.length - 1];
|
|
3628
|
+
if (sequence <= lastCacheItem.sequence) {
|
|
3629
|
+
cache.length = 0;
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
cache.push({ content: message, sequence });
|
|
3633
|
+
while (cache.length > this.maxMessagesPerKey) {
|
|
3634
|
+
cache.shift();
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
/**
|
|
3638
|
+
* Check if we have a valid base
|
|
3639
|
+
*/
|
|
3640
|
+
hasBase() {
|
|
3641
|
+
if (this.conflationKey) {
|
|
3642
|
+
return this.conflationCaches.size > 0;
|
|
3643
|
+
}
|
|
3644
|
+
return this.baseMessage !== null && this.baseSequence !== null;
|
|
3645
|
+
}
|
|
3646
|
+
/**
|
|
3647
|
+
* Validate sequence number
|
|
3648
|
+
*/
|
|
3649
|
+
isValidSequence(sequence) {
|
|
3650
|
+
if (this.lastSequence === null) {
|
|
3651
|
+
return true;
|
|
3652
|
+
}
|
|
3653
|
+
return sequence > this.lastSequence;
|
|
3654
|
+
}
|
|
3655
|
+
/**
|
|
3656
|
+
* Update sequence after processing a message
|
|
3657
|
+
*/
|
|
3658
|
+
updateSequence(sequence) {
|
|
3659
|
+
this.lastSequence = sequence;
|
|
3660
|
+
}
|
|
3661
|
+
/**
|
|
3662
|
+
* Record delta received
|
|
3663
|
+
*/
|
|
3664
|
+
recordDelta() {
|
|
3665
|
+
this.deltaCount++;
|
|
3666
|
+
}
|
|
3667
|
+
/**
|
|
3668
|
+
* Record full message received
|
|
3669
|
+
*/
|
|
3670
|
+
recordFullMessage() {
|
|
3671
|
+
this.fullMessageCount++;
|
|
3672
|
+
}
|
|
3673
|
+
/**
|
|
3674
|
+
* Get statistics
|
|
3675
|
+
*/
|
|
3676
|
+
getStats() {
|
|
3677
|
+
return {
|
|
3678
|
+
channelName: this.channelName,
|
|
3679
|
+
conflationKey: this.conflationKey,
|
|
3680
|
+
conflationGroupCount: this.conflationCaches.size,
|
|
3681
|
+
deltaCount: this.deltaCount,
|
|
3682
|
+
fullMessageCount: this.fullMessageCount,
|
|
3683
|
+
totalMessages: this.deltaCount + this.fullMessageCount
|
|
3684
|
+
};
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
const fossilDeltaGlobal = typeof window !== "undefined" ? window.fossilDelta : void 0;
|
|
3688
|
+
const vcdiffGlobal = typeof window !== "undefined" ? window.vcdiff : void 0;
|
|
3689
|
+
function base64ToBytes(base642) {
|
|
3690
|
+
const binaryString = atob(base642);
|
|
3691
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
3692
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
3693
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
3694
|
+
}
|
|
3695
|
+
return bytes;
|
|
3696
|
+
}
|
|
3697
|
+
function bytesToString(bytes) {
|
|
3698
|
+
if (Array.isArray(bytes) || !(bytes instanceof Uint8Array)) {
|
|
3699
|
+
bytes = new Uint8Array(bytes);
|
|
3700
|
+
}
|
|
3701
|
+
return new TextDecoder().decode(bytes);
|
|
3702
|
+
}
|
|
3703
|
+
function stringToBytes(str) {
|
|
3704
|
+
return new TextEncoder().encode(str);
|
|
3705
|
+
}
|
|
3706
|
+
class FossilDeltaDecoder {
|
|
3707
|
+
static isAvailable() {
|
|
3708
|
+
return typeof fossilDelta.applyDelta !== "undefined" || typeof fossilDeltaGlobal !== "undefined" && fossilDeltaGlobal.apply;
|
|
3709
|
+
}
|
|
3710
|
+
static apply(base, delta) {
|
|
3711
|
+
if (!this.isAvailable()) {
|
|
3712
|
+
throw new Error("Fossil Delta library not loaded");
|
|
3713
|
+
}
|
|
3714
|
+
const baseBytes = typeof base === "string" ? stringToBytes(base) : base;
|
|
3715
|
+
const deltaBytes = typeof delta === "string" ? stringToBytes(delta) : delta;
|
|
3716
|
+
try {
|
|
3717
|
+
let result;
|
|
3718
|
+
if (typeof fossilDelta.applyDelta !== "undefined") {
|
|
3719
|
+
result = fossilDelta.applyDelta(baseBytes, deltaBytes);
|
|
3720
|
+
} else if (fossilDeltaGlobal && fossilDeltaGlobal.apply) {
|
|
3721
|
+
result = fossilDeltaGlobal.apply(baseBytes, deltaBytes);
|
|
3722
|
+
} else {
|
|
3723
|
+
throw new Error("No fossil-delta implementation found");
|
|
3724
|
+
}
|
|
3725
|
+
return bytesToString(result);
|
|
3726
|
+
} catch (error) {
|
|
3727
|
+
throw new Error(
|
|
3728
|
+
`Fossil delta decode failed: ${error.message} (base=${baseBytes.length}B delta=${deltaBytes.length}B)`
|
|
3729
|
+
);
|
|
3730
|
+
}
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
class Xdelta3Decoder {
|
|
3734
|
+
static isAvailable() {
|
|
3735
|
+
return typeof vcdiffDecoder.decode !== "undefined" || typeof vcdiffGlobal !== "undefined" && vcdiffGlobal.decode;
|
|
3736
|
+
}
|
|
3737
|
+
static apply(base, delta) {
|
|
3738
|
+
if (!this.isAvailable()) {
|
|
3739
|
+
throw new Error("Xdelta3/VCDIFF library not loaded");
|
|
3740
|
+
}
|
|
3741
|
+
const baseBytes = typeof base === "string" ? stringToBytes(base) : base;
|
|
3742
|
+
const deltaBytes = typeof delta === "string" ? stringToBytes(delta) : delta;
|
|
3743
|
+
try {
|
|
3744
|
+
let result;
|
|
3745
|
+
if (typeof vcdiffDecoder.decode !== "undefined") {
|
|
3746
|
+
result = vcdiffDecoder.decode(deltaBytes, baseBytes);
|
|
3747
|
+
} else if (vcdiffGlobal && vcdiffGlobal.decode) {
|
|
3748
|
+
result = vcdiffGlobal.decode(deltaBytes, baseBytes);
|
|
3749
|
+
} else {
|
|
3750
|
+
throw new Error("No VCDIFF decoder implementation found");
|
|
3751
|
+
}
|
|
3752
|
+
return bytesToString(result);
|
|
3753
|
+
} catch (error) {
|
|
3754
|
+
throw new Error(
|
|
3755
|
+
`Xdelta3 decode failed: ${error.message} (base=${baseBytes.length}B delta=${deltaBytes.length}B)`
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
class DeltaCompressionManager {
|
|
3761
|
+
constructor(options = {}, sendEventCallback) {
|
|
3762
|
+
this.options = {
|
|
3763
|
+
enabled: options.enabled !== false,
|
|
3764
|
+
algorithms: options.algorithms || ["fossil", "xdelta3"],
|
|
3765
|
+
debug: options.debug || false,
|
|
3766
|
+
onStats: options.onStats || null,
|
|
3767
|
+
onError: options.onError || null
|
|
3768
|
+
};
|
|
3769
|
+
this.enabled = false;
|
|
3770
|
+
this.channelStates = /* @__PURE__ */ new Map();
|
|
3771
|
+
this.stats = {
|
|
3772
|
+
totalMessages: 0,
|
|
3773
|
+
deltaMessages: 0,
|
|
3774
|
+
fullMessages: 0,
|
|
3775
|
+
totalBytesWithoutCompression: 0,
|
|
3776
|
+
totalBytesWithCompression: 0,
|
|
3777
|
+
errors: 0
|
|
3778
|
+
};
|
|
3779
|
+
this.sendEventCallback = sendEventCallback;
|
|
3780
|
+
this.availableAlgorithms = this.detectAvailableAlgorithms();
|
|
3781
|
+
if (this.availableAlgorithms.length === 0) {
|
|
3782
|
+
Logger$1.warn(
|
|
3783
|
+
"[DeltaCompression] No delta algorithms available. Please include fossil-delta or vcdiff-decoder libraries."
|
|
3784
|
+
);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
/**
|
|
3788
|
+
* Detect which algorithm libraries are loaded
|
|
3789
|
+
*/
|
|
3790
|
+
detectAvailableAlgorithms() {
|
|
3791
|
+
const available = [];
|
|
3792
|
+
if (FossilDeltaDecoder.isAvailable()) {
|
|
3793
|
+
available.push("fossil");
|
|
3794
|
+
this.log("Fossil Delta decoder available");
|
|
3795
|
+
}
|
|
3796
|
+
if (Xdelta3Decoder.isAvailable()) {
|
|
3797
|
+
available.push("xdelta3");
|
|
3798
|
+
this.log("Xdelta3 decoder available");
|
|
3799
|
+
}
|
|
3800
|
+
return available;
|
|
3801
|
+
}
|
|
3802
|
+
/**
|
|
3803
|
+
* Enable delta compression
|
|
3804
|
+
*/
|
|
3805
|
+
enable() {
|
|
3806
|
+
if (this.enabled || !this.options.enabled) {
|
|
3807
|
+
return;
|
|
3808
|
+
}
|
|
3809
|
+
if (this.availableAlgorithms.length === 0) {
|
|
3810
|
+
this.log("No delta algorithms available, cannot enable");
|
|
3811
|
+
return;
|
|
3812
|
+
}
|
|
3813
|
+
const supportedAlgorithms = this.availableAlgorithms.filter(
|
|
3814
|
+
(algo) => this.options.algorithms.includes(algo)
|
|
3815
|
+
);
|
|
3816
|
+
if (supportedAlgorithms.length === 0) {
|
|
3817
|
+
this.log("No mutually supported algorithms");
|
|
3818
|
+
return;
|
|
3819
|
+
}
|
|
3820
|
+
this.log("Sending enable request", supportedAlgorithms);
|
|
3821
|
+
this.sendEventCallback("pusher:enable_delta_compression", {
|
|
3822
|
+
algorithms: supportedAlgorithms
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
/**
|
|
3826
|
+
* Disable delta compression
|
|
3827
|
+
* Note: We intentionally do NOT clear channelStates here.
|
|
3828
|
+
* This allows state to be preserved across enable/disable cycles,
|
|
3829
|
+
* which is important for reconnection scenarios and user toggling.
|
|
3830
|
+
* Use clearChannelState() if you need to explicitly clear state.
|
|
3831
|
+
*/
|
|
3832
|
+
disable() {
|
|
3833
|
+
this.enabled = false;
|
|
3834
|
+
}
|
|
3835
|
+
/**
|
|
3836
|
+
* Handle delta compression enabled confirmation
|
|
3837
|
+
*/
|
|
3838
|
+
handleEnabled(data) {
|
|
3839
|
+
this.enabled = data.enabled || true;
|
|
3840
|
+
this.log("Delta compression enabled", data);
|
|
3841
|
+
}
|
|
3842
|
+
/**
|
|
3843
|
+
* Handle cache sync message (conflation keys)
|
|
3844
|
+
*/
|
|
3845
|
+
handleCacheSync(channel, data) {
|
|
3846
|
+
this.log("Received cache sync", {
|
|
3847
|
+
channel,
|
|
3848
|
+
conflationKey: data.conflation_key,
|
|
3849
|
+
groupCount: Object.keys(data.states || {}).length
|
|
3850
|
+
});
|
|
3851
|
+
let channelState = this.channelStates.get(channel);
|
|
3852
|
+
if (!channelState) {
|
|
3853
|
+
channelState = new ChannelState(channel);
|
|
3854
|
+
this.channelStates.set(channel, channelState);
|
|
3855
|
+
}
|
|
3856
|
+
channelState.initializeFromCacheSync(data);
|
|
3857
|
+
this.log("Cache initialized", channelState.getStats());
|
|
3858
|
+
}
|
|
3859
|
+
/**
|
|
3860
|
+
* Handle delta-compressed message
|
|
3861
|
+
*/
|
|
3862
|
+
handleDeltaMessage(channel, deltaData) {
|
|
3863
|
+
let deltaBytes = null;
|
|
3864
|
+
try {
|
|
3865
|
+
const event = deltaData.event;
|
|
3866
|
+
const delta = deltaData.delta;
|
|
3867
|
+
const sequence = deltaData.seq;
|
|
3868
|
+
const algorithm = deltaData.algorithm || "fossil";
|
|
3869
|
+
const conflationKey = deltaData.conflation_key;
|
|
3870
|
+
const baseIndex = deltaData.base_index;
|
|
3871
|
+
this.log("Received delta message", {
|
|
3872
|
+
channel,
|
|
3873
|
+
event,
|
|
3874
|
+
sequence,
|
|
3875
|
+
algorithm,
|
|
3876
|
+
conflationKey,
|
|
3877
|
+
baseIndex,
|
|
3878
|
+
deltaSize: delta.length
|
|
3879
|
+
});
|
|
3880
|
+
let channelState = this.channelStates.get(channel);
|
|
3881
|
+
if (!channelState) {
|
|
3882
|
+
this.log(`Ignoring delta for unsubscribed channel: ${channel}`);
|
|
3883
|
+
return null;
|
|
3884
|
+
}
|
|
3885
|
+
let baseMessage;
|
|
3886
|
+
if (channelState.conflationKey) {
|
|
3887
|
+
baseMessage = channelState.getBaseMessage(conflationKey, baseIndex);
|
|
3888
|
+
if (!baseMessage) {
|
|
3889
|
+
this.error(
|
|
3890
|
+
`No base message for channel ${channel}, key ${conflationKey}, index ${baseIndex}`
|
|
3891
|
+
);
|
|
3892
|
+
if (this.options.debug) {
|
|
3893
|
+
this.log("Current conflation cache snapshot", {
|
|
3894
|
+
channel,
|
|
3895
|
+
conflationKey: channelState.conflationKey,
|
|
3896
|
+
cacheSizes: Array.from(
|
|
3897
|
+
channelState.conflationCaches.entries()
|
|
3898
|
+
).map(([key, cache]) => ({ key, size: cache.length }))
|
|
3899
|
+
});
|
|
3900
|
+
}
|
|
3901
|
+
this.requestResync(channel);
|
|
3902
|
+
return null;
|
|
3903
|
+
}
|
|
3904
|
+
} else {
|
|
3905
|
+
baseMessage = channelState.baseMessage;
|
|
3906
|
+
if (!baseMessage) {
|
|
3907
|
+
this.error(`No base message for channel ${channel}`);
|
|
3908
|
+
if (this.options.debug) {
|
|
3909
|
+
this.log("Channel state missing base", {
|
|
3910
|
+
channel,
|
|
3911
|
+
lastSequence: channelState.lastSequence
|
|
3912
|
+
});
|
|
3913
|
+
}
|
|
3914
|
+
this.requestResync(channel);
|
|
3915
|
+
return null;
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
deltaBytes = base64ToBytes(delta);
|
|
3919
|
+
let reconstructedMessage;
|
|
3920
|
+
try {
|
|
3921
|
+
if (algorithm === "fossil") {
|
|
3922
|
+
reconstructedMessage = FossilDeltaDecoder.apply(
|
|
3923
|
+
baseMessage,
|
|
3924
|
+
deltaBytes
|
|
3925
|
+
);
|
|
3926
|
+
} else if (algorithm === "xdelta3") {
|
|
3927
|
+
reconstructedMessage = Xdelta3Decoder.apply(baseMessage, deltaBytes);
|
|
3928
|
+
} else {
|
|
3929
|
+
throw Error(`Unknown algorithm: ${algorithm}`);
|
|
3930
|
+
}
|
|
3931
|
+
} catch (decodeError) {
|
|
3932
|
+
throw decodeError;
|
|
3933
|
+
}
|
|
3934
|
+
if (channelState.conflationKey) {
|
|
3935
|
+
channelState.updateConflationCache(
|
|
3936
|
+
conflationKey,
|
|
3937
|
+
reconstructedMessage,
|
|
3938
|
+
sequence
|
|
3939
|
+
);
|
|
3940
|
+
} else {
|
|
3941
|
+
channelState.setBase(reconstructedMessage, sequence);
|
|
3942
|
+
}
|
|
3943
|
+
channelState.updateSequence(sequence);
|
|
3944
|
+
channelState.recordDelta();
|
|
3945
|
+
this.stats.totalMessages++;
|
|
3946
|
+
this.stats.deltaMessages++;
|
|
3947
|
+
this.stats.totalBytesWithCompression += deltaBytes.length;
|
|
3948
|
+
this.stats.totalBytesWithoutCompression += reconstructedMessage.length;
|
|
3949
|
+
this.updateStats();
|
|
3950
|
+
this.log("Delta applied successfully", {
|
|
3951
|
+
channel,
|
|
3952
|
+
event,
|
|
3953
|
+
conflationKey,
|
|
3954
|
+
originalSize: reconstructedMessage.length,
|
|
3955
|
+
deltaSize: deltaBytes.length,
|
|
3956
|
+
compressionRatio: (deltaBytes.length / reconstructedMessage.length * 100).toFixed(1) + "%"
|
|
3957
|
+
});
|
|
3958
|
+
try {
|
|
3959
|
+
const parsedMessage = JSON.parse(reconstructedMessage);
|
|
3960
|
+
return {
|
|
3961
|
+
event,
|
|
3962
|
+
channel,
|
|
3963
|
+
data: parsedMessage.data || parsedMessage
|
|
3964
|
+
};
|
|
3965
|
+
} catch (e) {
|
|
3966
|
+
return {
|
|
3967
|
+
event,
|
|
3968
|
+
channel,
|
|
3969
|
+
data: reconstructedMessage
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
} catch (error) {
|
|
3973
|
+
this.error("Delta decode failed", {
|
|
3974
|
+
channel,
|
|
3975
|
+
event: deltaData.event,
|
|
3976
|
+
sequence: deltaData.seq,
|
|
3977
|
+
algorithm: deltaData.algorithm,
|
|
3978
|
+
conflationKey: deltaData.conflation_key,
|
|
3979
|
+
baseIndex: deltaData.base_index,
|
|
3980
|
+
deltaSize: deltaData.delta?.length,
|
|
3981
|
+
decodedDeltaBytes: deltaBytes ? deltaBytes.length : "n/a",
|
|
3982
|
+
message: error.message
|
|
3983
|
+
});
|
|
3984
|
+
this.stats.errors++;
|
|
3985
|
+
return null;
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
/**
|
|
3989
|
+
* Handle regular (full) message with delta sequence markers
|
|
3990
|
+
*/
|
|
3991
|
+
handleFullMessage(channel, rawMessage, sequence, conflationKey) {
|
|
3992
|
+
if (!sequence && sequence !== 0) {
|
|
3993
|
+
try {
|
|
3994
|
+
const parsed = JSON.parse(rawMessage);
|
|
3995
|
+
const candidate = typeof parsed.data === "string" ? JSON.parse(parsed.data).__delta_seq ?? parsed.__delta_seq : parsed.data?.__delta_seq ?? parsed.__delta_seq;
|
|
3996
|
+
if (candidate === 0 || candidate) {
|
|
3997
|
+
sequence = candidate;
|
|
3998
|
+
} else {
|
|
3999
|
+
this.log("handleFullMessage missing sequence, skipping", {
|
|
4000
|
+
channel,
|
|
4001
|
+
hasSequence: false
|
|
4002
|
+
});
|
|
4003
|
+
return;
|
|
4004
|
+
}
|
|
4005
|
+
} catch (e) {
|
|
4006
|
+
this.log("handleFullMessage missing sequence and parse failed", {
|
|
4007
|
+
channel,
|
|
4008
|
+
hasSequence: false
|
|
4009
|
+
});
|
|
4010
|
+
return;
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
const messageSize = rawMessage.length;
|
|
4014
|
+
let channelState = this.channelStates.get(channel);
|
|
4015
|
+
if (!channelState) {
|
|
4016
|
+
channelState = new ChannelState(channel);
|
|
4017
|
+
this.channelStates.set(channel, channelState);
|
|
4018
|
+
}
|
|
4019
|
+
const finalConflationKey = conflationKey;
|
|
4020
|
+
if (finalConflationKey !== void 0 && !channelState.conflationKey) {
|
|
4021
|
+
channelState.conflationKey = "enabled";
|
|
4022
|
+
}
|
|
4023
|
+
if (channelState.conflationKey && finalConflationKey !== void 0) {
|
|
4024
|
+
channelState.updateConflationCache(
|
|
4025
|
+
finalConflationKey,
|
|
4026
|
+
rawMessage,
|
|
4027
|
+
// Store raw message directly
|
|
4028
|
+
sequence
|
|
4029
|
+
);
|
|
4030
|
+
this.log("Stored full message (conflation)", {
|
|
4031
|
+
channel,
|
|
4032
|
+
conflationKey: finalConflationKey,
|
|
4033
|
+
sequence,
|
|
4034
|
+
size: messageSize
|
|
4035
|
+
});
|
|
4036
|
+
} else {
|
|
4037
|
+
channelState.setBase(rawMessage, sequence);
|
|
4038
|
+
this.log("Stored full message", {
|
|
4039
|
+
channel,
|
|
4040
|
+
sequence,
|
|
4041
|
+
size: messageSize
|
|
4042
|
+
});
|
|
4043
|
+
}
|
|
4044
|
+
channelState.recordFullMessage();
|
|
4045
|
+
this.stats.totalMessages++;
|
|
4046
|
+
this.stats.fullMessages++;
|
|
4047
|
+
this.stats.totalBytesWithoutCompression += messageSize;
|
|
4048
|
+
this.stats.totalBytesWithCompression += messageSize;
|
|
4049
|
+
this.updateStats();
|
|
4050
|
+
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Request resync for a channel
|
|
4053
|
+
*/
|
|
4054
|
+
requestResync(channel) {
|
|
4055
|
+
this.log("Requesting resync for channel", channel);
|
|
4056
|
+
this.sendEventCallback("pusher:delta_sync_error", { channel });
|
|
4057
|
+
this.channelStates.delete(channel);
|
|
4058
|
+
}
|
|
4059
|
+
/**
|
|
4060
|
+
* Update and emit stats
|
|
4061
|
+
*/
|
|
4062
|
+
updateStats() {
|
|
4063
|
+
if (this.options.onStats) {
|
|
4064
|
+
this.options.onStats(this.getStats());
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
/**
|
|
4068
|
+
* Get current statistics
|
|
4069
|
+
*/
|
|
4070
|
+
getStats() {
|
|
4071
|
+
const bandwidthSaved = this.stats.totalBytesWithoutCompression - this.stats.totalBytesWithCompression;
|
|
4072
|
+
const bandwidthSavedPercent = this.stats.totalBytesWithoutCompression > 0 ? bandwidthSaved / this.stats.totalBytesWithoutCompression * 100 : 0;
|
|
4073
|
+
const channelStats = Array.from(this.channelStates.values()).map(
|
|
4074
|
+
(state) => state.getStats()
|
|
4075
|
+
);
|
|
4076
|
+
return {
|
|
4077
|
+
...this.stats,
|
|
4078
|
+
bandwidthSaved,
|
|
4079
|
+
bandwidthSavedPercent,
|
|
4080
|
+
channelCount: this.channelStates.size,
|
|
4081
|
+
channels: channelStats
|
|
4082
|
+
};
|
|
4083
|
+
}
|
|
4084
|
+
/**
|
|
4085
|
+
* Reset statistics
|
|
4086
|
+
*/
|
|
4087
|
+
resetStats() {
|
|
4088
|
+
this.stats = {
|
|
4089
|
+
totalMessages: 0,
|
|
4090
|
+
deltaMessages: 0,
|
|
4091
|
+
fullMessages: 0,
|
|
4092
|
+
totalBytesWithoutCompression: 0,
|
|
4093
|
+
totalBytesWithCompression: 0,
|
|
4094
|
+
errors: 0
|
|
4095
|
+
};
|
|
4096
|
+
this.updateStats();
|
|
4097
|
+
}
|
|
4098
|
+
/**
|
|
4099
|
+
* Clear channel state
|
|
4100
|
+
*/
|
|
4101
|
+
clearChannelState(channel) {
|
|
4102
|
+
if (channel) {
|
|
4103
|
+
this.channelStates.delete(channel);
|
|
4104
|
+
} else {
|
|
4105
|
+
this.channelStates.clear();
|
|
4106
|
+
}
|
|
4107
|
+
}
|
|
4108
|
+
/**
|
|
4109
|
+
* Check if delta compression is enabled
|
|
4110
|
+
*/
|
|
4111
|
+
isEnabled() {
|
|
4112
|
+
return this.enabled;
|
|
4113
|
+
}
|
|
4114
|
+
/**
|
|
4115
|
+
* Get available algorithms
|
|
4116
|
+
*/
|
|
4117
|
+
getAvailableAlgorithms() {
|
|
4118
|
+
return this.availableAlgorithms;
|
|
4119
|
+
}
|
|
4120
|
+
/**
|
|
4121
|
+
* Log message (if debug enabled)
|
|
4122
|
+
*/
|
|
4123
|
+
log(...args) {
|
|
4124
|
+
if (this.options.debug) {
|
|
4125
|
+
Logger$1.debug("[DeltaCompression]", ...args);
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Log error
|
|
4130
|
+
*/
|
|
4131
|
+
error(...args) {
|
|
4132
|
+
Logger$1.error("[DeltaCompression]", ...args);
|
|
4133
|
+
if (this.options.onError) {
|
|
4134
|
+
this.options.onError(args);
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
class Pusher {
|
|
4139
|
+
static {
|
|
4140
|
+
this.instances = [];
|
|
4141
|
+
}
|
|
4142
|
+
static {
|
|
4143
|
+
this.isReady = false;
|
|
4144
|
+
}
|
|
4145
|
+
static {
|
|
4146
|
+
this._logToConsole = false;
|
|
4147
|
+
}
|
|
4148
|
+
static get logToConsole() {
|
|
4149
|
+
return this._logToConsole;
|
|
4150
|
+
}
|
|
4151
|
+
static set logToConsole(value) {
|
|
4152
|
+
this._logToConsole = value;
|
|
4153
|
+
setLoggerConfig({ logToConsole: value, log: this._log });
|
|
4154
|
+
}
|
|
4155
|
+
static get log() {
|
|
4156
|
+
return this._log;
|
|
4157
|
+
}
|
|
4158
|
+
static set log(fn) {
|
|
4159
|
+
this._log = fn;
|
|
4160
|
+
setLoggerConfig({ logToConsole: this._logToConsole, log: fn });
|
|
4161
|
+
}
|
|
4162
|
+
static {
|
|
4163
|
+
this.Runtime = NodeJS;
|
|
4164
|
+
}
|
|
4165
|
+
static {
|
|
4166
|
+
this.ScriptReceivers = NodeJS.ScriptReceivers;
|
|
4167
|
+
}
|
|
4168
|
+
static {
|
|
4169
|
+
this.DependenciesReceivers = NodeJS.DependenciesReceivers;
|
|
4170
|
+
}
|
|
4171
|
+
static {
|
|
4172
|
+
this.auth_callbacks = NodeJS.auth_callbacks;
|
|
4173
|
+
}
|
|
4174
|
+
static ready() {
|
|
4175
|
+
Pusher.isReady = true;
|
|
4176
|
+
for (var i = 0, l = Pusher.instances.length; i < l; i++) {
|
|
4177
|
+
Pusher.instances[i].connect();
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
static getClientFeatures() {
|
|
4181
|
+
return keys(
|
|
4182
|
+
filterObject({ ws: NodeJS.Transports.ws }, function(t) {
|
|
4183
|
+
return t.isSupported({});
|
|
4184
|
+
})
|
|
4185
|
+
);
|
|
4186
|
+
}
|
|
4187
|
+
constructor(app_key, options) {
|
|
4188
|
+
checkAppKey(app_key);
|
|
4189
|
+
validateOptions(options);
|
|
4190
|
+
this.key = app_key;
|
|
4191
|
+
this.config = getConfig(options, this);
|
|
4192
|
+
this.channels = Factory.createChannels();
|
|
4193
|
+
this.global_emitter = new Dispatcher();
|
|
4194
|
+
this.sessionID = NodeJS.randomInt(1e9);
|
|
4195
|
+
this.timeline = new Timeline(this.key, this.sessionID, {
|
|
4196
|
+
cluster: this.config.cluster,
|
|
4197
|
+
features: Pusher.getClientFeatures(),
|
|
4198
|
+
params: this.config.timelineParams || {},
|
|
4199
|
+
limit: 50,
|
|
4200
|
+
level: TimelineLevel.INFO,
|
|
4201
|
+
version: Defaults.VERSION
|
|
4202
|
+
});
|
|
4203
|
+
if (this.config.enableStats) {
|
|
4204
|
+
this.timelineSender = Factory.createTimelineSender(this.timeline, {
|
|
4205
|
+
host: this.config.statsHost,
|
|
4206
|
+
path: "/timeline/v2/" + NodeJS.TimelineTransport.name
|
|
4207
|
+
});
|
|
4208
|
+
}
|
|
4209
|
+
var getStrategy = (options2) => {
|
|
4210
|
+
return NodeJS.getDefaultStrategy(this.config, options2, defineTransport);
|
|
4211
|
+
};
|
|
4212
|
+
this.connection = Factory.createConnectionManager(this.key, {
|
|
4213
|
+
getStrategy,
|
|
4214
|
+
timeline: this.timeline,
|
|
4215
|
+
activityTimeout: this.config.activityTimeout,
|
|
4216
|
+
pongTimeout: this.config.pongTimeout,
|
|
4217
|
+
unavailableTimeout: this.config.unavailableTimeout,
|
|
4218
|
+
useTLS: Boolean(this.config.useTLS)
|
|
4219
|
+
});
|
|
4220
|
+
if (options.deltaCompression !== void 0) {
|
|
4221
|
+
this.deltaCompression = new DeltaCompressionManager(
|
|
4222
|
+
options.deltaCompression || {},
|
|
4223
|
+
(event, data) => this.send_event(event, data)
|
|
4224
|
+
);
|
|
4225
|
+
}
|
|
4226
|
+
this.connection.bind("connected", () => {
|
|
4227
|
+
this.subscribeAll();
|
|
4228
|
+
if (this.timelineSender) {
|
|
4229
|
+
this.timelineSender.send(this.connection.isUsingTLS());
|
|
4230
|
+
}
|
|
4231
|
+
if (this.deltaCompression && options.deltaCompression?.enabled === true) {
|
|
4232
|
+
this.deltaCompression.enable();
|
|
4233
|
+
}
|
|
4234
|
+
});
|
|
4235
|
+
this.connection.bind("message", (event) => {
|
|
4236
|
+
var eventName = event.event;
|
|
4237
|
+
var internal = eventName.indexOf("pusher_internal:") === 0;
|
|
4238
|
+
if (this.deltaCompression) {
|
|
4239
|
+
if (eventName === "pusher:delta_compression_enabled") {
|
|
4240
|
+
this.deltaCompression.handleEnabled(event.data);
|
|
4241
|
+
} else if (eventName === "pusher:delta_cache_sync" && event.channel) {
|
|
4242
|
+
this.deltaCompression.handleCacheSync(event.channel, event.data);
|
|
4243
|
+
return;
|
|
4244
|
+
} else if (eventName === "pusher:delta" && event.channel) {
|
|
4245
|
+
var channel = this.channel(event.channel);
|
|
4246
|
+
if (!channel) {
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4249
|
+
const reconstructedEvent = this.deltaCompression.handleDeltaMessage(
|
|
4250
|
+
event.channel,
|
|
4251
|
+
event.data
|
|
4252
|
+
);
|
|
4253
|
+
if (reconstructedEvent) {
|
|
4254
|
+
if (channel) {
|
|
4255
|
+
channel.handleEvent(reconstructedEvent);
|
|
4256
|
+
}
|
|
4257
|
+
this.global_emitter.emit(
|
|
4258
|
+
reconstructedEvent.event,
|
|
4259
|
+
reconstructedEvent.data
|
|
4260
|
+
);
|
|
4261
|
+
}
|
|
4262
|
+
return;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
if (event.channel) {
|
|
4266
|
+
var channel = this.channel(event.channel);
|
|
4267
|
+
if (channel) {
|
|
4268
|
+
channel.handleEvent(event);
|
|
4269
|
+
}
|
|
4270
|
+
if (this.deltaCompression && event.event && !event.event.startsWith("pusher:") && !event.event.startsWith("pusher_internal:")) {
|
|
4271
|
+
let sequence;
|
|
4272
|
+
if (typeof event.sequence === "number") {
|
|
4273
|
+
sequence = event.sequence;
|
|
4274
|
+
}
|
|
4275
|
+
let conflationKey;
|
|
4276
|
+
if (typeof event.conflation_key === "string") {
|
|
4277
|
+
conflationKey = event.conflation_key;
|
|
4278
|
+
}
|
|
4279
|
+
let fullMessage = event.rawMessage || "";
|
|
4280
|
+
if (fullMessage && sequence !== void 0) {
|
|
4281
|
+
fullMessage = fullMessage.replace(/,"__delta_seq":\d+/g, "");
|
|
4282
|
+
fullMessage = fullMessage.replace(/"__delta_seq":\d+,/g, "");
|
|
4283
|
+
fullMessage = fullMessage.replace(
|
|
4284
|
+
/,"__conflation_key":"[^"]*"/g,
|
|
4285
|
+
""
|
|
4286
|
+
);
|
|
4287
|
+
fullMessage = fullMessage.replace(
|
|
4288
|
+
/"__conflation_key":"[^"]*",/g,
|
|
4289
|
+
""
|
|
4290
|
+
);
|
|
4291
|
+
}
|
|
4292
|
+
this.deltaCompression.handleFullMessage(
|
|
4293
|
+
event.channel,
|
|
4294
|
+
fullMessage,
|
|
4295
|
+
sequence,
|
|
4296
|
+
conflationKey
|
|
4297
|
+
);
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
if (!internal) {
|
|
4301
|
+
this.global_emitter.emit(event.event, event.data);
|
|
4302
|
+
}
|
|
4303
|
+
});
|
|
4304
|
+
this.connection.bind("connecting", () => {
|
|
4305
|
+
this.channels.disconnect();
|
|
4306
|
+
});
|
|
4307
|
+
this.connection.bind("disconnected", () => {
|
|
4308
|
+
this.channels.disconnect();
|
|
4309
|
+
});
|
|
4310
|
+
this.connection.bind("error", (err) => {
|
|
4311
|
+
Logger$1.warn(err);
|
|
4312
|
+
});
|
|
4313
|
+
Pusher.instances.push(this);
|
|
4314
|
+
this.timeline.info({ instances: Pusher.instances.length });
|
|
4315
|
+
this.user = new UserFacade(this);
|
|
4316
|
+
if (Pusher.isReady) {
|
|
4317
|
+
this.connect();
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
channel(name) {
|
|
4321
|
+
return this.channels.find(name);
|
|
4322
|
+
}
|
|
4323
|
+
allChannels() {
|
|
4324
|
+
return this.channels.all();
|
|
4325
|
+
}
|
|
4326
|
+
connect() {
|
|
4327
|
+
this.connection.connect();
|
|
4328
|
+
if (this.timelineSender) {
|
|
4329
|
+
if (!this.timelineSenderTimer) {
|
|
4330
|
+
var usingTLS = this.connection.isUsingTLS();
|
|
4331
|
+
var timelineSender = this.timelineSender;
|
|
4332
|
+
this.timelineSenderTimer = new PeriodicTimer(6e4, function() {
|
|
4333
|
+
timelineSender.send(usingTLS);
|
|
4334
|
+
});
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
disconnect() {
|
|
4339
|
+
this.connection.disconnect();
|
|
4340
|
+
if (this.timelineSenderTimer) {
|
|
4341
|
+
this.timelineSenderTimer.ensureAborted();
|
|
4342
|
+
this.timelineSenderTimer = null;
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4345
|
+
bind(event_name, callback, context) {
|
|
4346
|
+
this.global_emitter.bind(event_name, callback, context);
|
|
4347
|
+
return this;
|
|
4348
|
+
}
|
|
4349
|
+
unbind(event_name, callback, context) {
|
|
4350
|
+
this.global_emitter.unbind(event_name, callback, context);
|
|
4351
|
+
return this;
|
|
4352
|
+
}
|
|
4353
|
+
bind_global(callback) {
|
|
4354
|
+
this.global_emitter.bind_global(callback);
|
|
4355
|
+
return this;
|
|
4356
|
+
}
|
|
4357
|
+
unbind_global(callback) {
|
|
4358
|
+
this.global_emitter.unbind_global(callback);
|
|
4359
|
+
return this;
|
|
4360
|
+
}
|
|
4361
|
+
unbind_all(callback) {
|
|
4362
|
+
this.global_emitter.unbind_all();
|
|
4363
|
+
return this;
|
|
4364
|
+
}
|
|
4365
|
+
subscribeAll() {
|
|
4366
|
+
var channelName;
|
|
4367
|
+
for (channelName in this.channels.channels) {
|
|
4368
|
+
if (this.channels.channels.hasOwnProperty(channelName)) {
|
|
4369
|
+
this.subscribe(channelName);
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
subscribe(channel_name, tagsFilter) {
|
|
4374
|
+
var channel = this.channels.add(channel_name, this);
|
|
4375
|
+
if (tagsFilter) {
|
|
4376
|
+
channel.tagsFilter = tagsFilter;
|
|
4377
|
+
}
|
|
4378
|
+
if (channel.subscriptionPending && channel.subscriptionCancelled) {
|
|
4379
|
+
channel.reinstateSubscription();
|
|
4380
|
+
} else if (!channel.subscriptionPending && this.connection.state === "connected") {
|
|
4381
|
+
channel.subscribe();
|
|
4382
|
+
}
|
|
4383
|
+
return channel;
|
|
4384
|
+
}
|
|
4385
|
+
unsubscribe(channel_name) {
|
|
4386
|
+
var channel = this.channels.find(channel_name);
|
|
4387
|
+
if (channel && channel.subscriptionPending) {
|
|
4388
|
+
channel.cancelSubscription();
|
|
4389
|
+
} else {
|
|
4390
|
+
channel = this.channels.remove(channel_name);
|
|
4391
|
+
if (channel && channel.subscribed) {
|
|
4392
|
+
channel.unsubscribe();
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
if (this.deltaCompression) {
|
|
4396
|
+
this.deltaCompression.clearChannelState(channel_name);
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
send_event(event_name, data, channel) {
|
|
4400
|
+
return this.connection.send_event(event_name, data, channel);
|
|
4401
|
+
}
|
|
4402
|
+
shouldUseTLS() {
|
|
4403
|
+
return this.config.useTLS;
|
|
4404
|
+
}
|
|
4405
|
+
signin() {
|
|
4406
|
+
this.user.signin();
|
|
4407
|
+
}
|
|
4408
|
+
/**
|
|
4409
|
+
* Get delta compression statistics
|
|
4410
|
+
* @returns {DeltaStats} Statistics about delta compression bandwidth savings
|
|
4411
|
+
*/
|
|
4412
|
+
getDeltaStats() {
|
|
4413
|
+
if (!this.deltaCompression) {
|
|
4414
|
+
return null;
|
|
4415
|
+
}
|
|
4416
|
+
return this.deltaCompression.getStats();
|
|
4417
|
+
}
|
|
4418
|
+
/**
|
|
4419
|
+
* Reset delta compression statistics
|
|
4420
|
+
*/
|
|
4421
|
+
resetDeltaStats() {
|
|
4422
|
+
if (this.deltaCompression) {
|
|
4423
|
+
this.deltaCompression.resetStats();
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
function checkAppKey(key) {
|
|
4428
|
+
if (key === null || key === void 0) {
|
|
4429
|
+
throw "You must pass your app key when you instantiate Pusher.";
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
NodeJS.setup(Pusher);
|
|
4433
|
+
module.exports = Pusher;
|
|
4434
|
+
//# sourceMappingURL=pusher.js.map
|