Socket fixes and config options(#485)

This commit is contained in:
advo-kat 2023-02-10 18:59:20 +11:00 committed by GitHub
parent 64b0d47897
commit 8d9c75824c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 273 additions and 23 deletions

93
poetry.lock generated
View File

@ -976,14 +976,14 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam
[[package]]
name = "tenacity"
version = "8.2.0"
version = "8.2.1"
description = "Retry code until it succeeds"
category = "main"
optional = false
python-versions = ">=3.6"
files = [
{file = "tenacity-8.2.0-py3-none-any.whl", hash = "sha256:b723061a78ed0f4524190eae321d3d84100227d51c5677035b6615d91895e0d6"},
{file = "tenacity-8.2.0.tar.gz", hash = "sha256:a43bcd8910406e0884ca0db3db7bed581f389c1d05165e992a1ddabfc81df05e"},
{file = "tenacity-8.2.1-py3-none-any.whl", hash = "sha256:dd1b769ca7002fda992322939feca5bee4fa11f39146b0af14e0b8d9f27ea854"},
{file = "tenacity-8.2.1.tar.gz", hash = "sha256:c7bb4b86425b977726a7b49971542d4f67baf72096597d283f3ffd01f33b92df"},
]
[package.extras]
@ -1100,16 +1100,95 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
[package.extras]
standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
[[package]]
name = "websockets"
version = "10.4"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "websockets-10.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48"},
{file = "websockets-10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab"},
{file = "websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c"},
{file = "websockets-10.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032"},
{file = "websockets-10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4"},
{file = "websockets-10.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50"},
{file = "websockets-10.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8"},
{file = "websockets-10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1"},
{file = "websockets-10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331"},
{file = "websockets-10.4-cp310-cp310-win32.whl", hash = "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a"},
{file = "websockets-10.4-cp310-cp310-win_amd64.whl", hash = "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089"},
{file = "websockets-10.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4"},
{file = "websockets-10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f"},
{file = "websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c"},
{file = "websockets-10.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46"},
{file = "websockets-10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96"},
{file = "websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa"},
{file = "websockets-10.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c"},
{file = "websockets-10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106"},
{file = "websockets-10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9"},
{file = "websockets-10.4-cp311-cp311-win32.whl", hash = "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8"},
{file = "websockets-10.4-cp311-cp311-win_amd64.whl", hash = "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882"},
{file = "websockets-10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb"},
{file = "websockets-10.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc"},
{file = "websockets-10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033"},
{file = "websockets-10.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41"},
{file = "websockets-10.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df"},
{file = "websockets-10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea"},
{file = "websockets-10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c"},
{file = "websockets-10.4-cp37-cp37m-win32.whl", hash = "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038"},
{file = "websockets-10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28"},
{file = "websockets-10.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94"},
{file = "websockets-10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63"},
{file = "websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf"},
{file = "websockets-10.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6"},
{file = "websockets-10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8"},
{file = "websockets-10.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b"},
{file = "websockets-10.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c"},
{file = "websockets-10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b"},
{file = "websockets-10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56"},
{file = "websockets-10.4-cp38-cp38-win32.whl", hash = "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a"},
{file = "websockets-10.4-cp38-cp38-win_amd64.whl", hash = "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6"},
{file = "websockets-10.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f"},
{file = "websockets-10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112"},
{file = "websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f"},
{file = "websockets-10.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d"},
{file = "websockets-10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4"},
{file = "websockets-10.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0"},
{file = "websockets-10.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c"},
{file = "websockets-10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269"},
{file = "websockets-10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b"},
{file = "websockets-10.4-cp39-cp39-win32.whl", hash = "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588"},
{file = "websockets-10.4-cp39-cp39-win_amd64.whl", hash = "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74"},
{file = "websockets-10.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193"},
{file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342"},
{file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179"},
{file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485"},
{file = "websockets-10.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631"},
{file = "websockets-10.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0"},
{file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393"},
{file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576"},
{file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f"},
{file = "websockets-10.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1"},
{file = "websockets-10.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4"},
{file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf"},
{file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3"},
{file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13"},
{file = "websockets-10.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72"},
{file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"},
]
[[package]]
name = "zipp"
version = "3.12.1"
version = "3.13.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "zipp-3.12.1-py3-none-any.whl", hash = "sha256:6c4fe274b8f85ec73c37a8e4e3fa00df9fb9335da96fb789e3b96b318e5097b3"},
{file = "zipp-3.12.1.tar.gz", hash = "sha256:a3cac813d40993596b39ea9e93a18e8a2076d5c378b8bc88ec32ab264e04ad02"},
{file = "zipp-3.13.0-py3-none-any.whl", hash = "sha256:e8b2a36ea17df80ffe9e2c4fda3f693c3dad6df1697d3cd3af232db680950b0b"},
{file = "zipp-3.13.0.tar.gz", hash = "sha256:23f70e964bc11a34cef175bc90ba2914e1e4545ea1e3e2f67c079671883f9cb6"},
]
[package.extras]
@ -1119,4 +1198,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "2.0"
python-versions = "^3.7"
content-hash = "29af23359858d18a743ff85426e7496fb7e47bdda6d746294aea4a360df6e617"
content-hash = "0a0cbe4cdf4f07a69b36c76988a3ae25f7d3856a6ab40ace5ee0682c357723d8"

View File

@ -139,10 +139,14 @@ export const updateState = async (state, setState, result, setResult, router, so
* @param setResult The function to set the result.
* @param endpoint The endpoint to connect to.
*/
export const connect = async (socket, state, setState, result, setResult, router, endpoint) => {
export const connect = async (socket, state, setState, result, setResult, router, endpoint, transports) => {
// Get backend URL object from the endpoint
const endpoint_url = new URL(endpoint)
// Create the socket.
socket.current = io(endpoint, {
'path': '/event',
path: endpoint_url['pathname'],
transports: transports,
autoUnref: false,
});
// Once the socket is open, hydrate the page.

View File

@ -9,7 +9,7 @@ from .components import *
from .components.component import custom_component as component
from .components.graphing.victory import data
from .config import Config
from .constants import Env
from .constants import Env, Transports
from .event import EventChain, console_log, redirect, window_alert
from .middleware import Middleware
from .model import Model, session

View File

@ -35,6 +35,9 @@ class App(Base):
# The Socket.IO AsyncServer.
sio: Optional[AsyncServer] = None
# The socket app.
socket_app: Optional[ASGIApp] = None
# The state class to use for the app.
state: Type[State] = DefaultState
@ -47,7 +50,7 @@ class App(Base):
# Middleware to add to the app.
middleware: List[Middleware] = []
# events handlers to trigger when a page load
# Event handlers to trigger when a page loads.
load_events: Dict[str, EventHandler] = {}
def __init__(self, *args, **kwargs):
@ -59,6 +62,9 @@ class App(Base):
"""
super().__init__(*args, **kwargs)
# Get the config
config = utils.get_config()
# Add middleware.
self.middleware.append(HydrateMiddleware())
@ -68,21 +74,30 @@ class App(Base):
# Set up the API.
self.api = FastAPI()
# Set up CORS options.
cors_allowed_origins = config.cors_allowed_origins
if config.cors_allowed_origins == [constants.CORS_ALLOWED_ORIGINS]:
cors_allowed_origins = "*"
# Set up the Socket.IO AsyncServer.
self.sio = AsyncServer(async_mode="asgi", cors_allowed_origins="*")
self.sio = AsyncServer(
async_mode="asgi",
cors_allowed_origins=cors_allowed_origins,
cors_credentials=config.cors_credentials,
max_http_buffer_size=config.polling_max_http_buffer_size,
)
# Create the socket app. Note event endpoint constant replaces the default 'socket.io' path.
socket_app = ASGIApp(self.sio, socketio_path=str(constants.Endpoint.EVENT))
self.socket_app = ASGIApp(self.sio, socketio_path="")
# Create the event namespace and attach the main app. Not related to the path above.
event_namespace = EventNamespace("/event")
event_namespace.app = self
# Create the event namespace and attach the main app. Not related to any paths.
event_namespace = EventNamespace("/event", self)
# Register the event namespace with the socket.
self.sio.register_namespace(event_namespace)
# Mount the socket app with the API.
self.api.mount("/", socket_app)
self.api.mount(str(constants.Endpoint.EVENT), self.socket_app)
def __repr__(self) -> str:
"""Get the string representation of the app.
@ -324,12 +339,17 @@ class App(Base):
compiler.compile_components(custom_components)
async def process(app: App, event: Event) -> StateUpdate:
async def process(
app: App, event: Event, sid: str, headers: Dict, client_ip: str
) -> StateUpdate:
"""Process an event.
Args:
app: The app to process the event for.
event: The event to process.
sid: The Socket.IO session id.
headers: The client headers.
client_ip: The client_ip.
Returns:
The state update after processing the event.
@ -337,12 +357,15 @@ async def process(app: App, event: Event) -> StateUpdate:
# Get the state for the session.
state = app.state_manager.get_state(event.token)
# pass router_data to the state of the App
# Pass router_data to the state of the App.
state.router_data = event.router_data
# also pass router_data to all substates
for _, substate in state.substates.items():
substate.router_data = event.router_data
state.router_data[constants.RouteVar.CLIENT_TOKEN] = event.token
state.router_data[constants.RouteVar.SESSION_ID] = sid
state.router_data[constants.RouteVar.HEADERS] = headers
state.router_data[constants.RouteVar.CLIENT_IP] = client_ip
# Preprocess the event.
pre = app.preprocess(state, event)
@ -365,9 +388,19 @@ async def process(app: App, event: Event) -> StateUpdate:
class EventNamespace(AsyncNamespace):
"""The event namespace."""
# The backend API object.
# The application object.
app: App
def __init__(self, namespace: str, app: App):
"""Initialize the event namespace.
Args:
namespace: The namespace.
app: The application object.
"""
super().__init__(namespace)
self.app = app
def on_connect(self, sid, environ):
"""Event for when the websocket disconnects.
@ -395,8 +428,21 @@ class EventNamespace(AsyncNamespace):
# Get the event.
event = Event.parse_raw(data)
# Get the event environment.
assert self.app.sio is not None
environ = self.app.sio.get_environ(sid, self.namespace)
# Get the client headers.
headers = {
k.decode("utf-8"): v.decode("utf-8")
for (k, v) in environ["asgi.scope"]["headers"]
}
# Get the client IP
client_ip = environ["REMOTE_ADDR"]
# Process the event.
update = await process(self.app, event)
update = await process(self.app, event, sid, headers, client_ip)
# Emit the event.
await self.emit(str(constants.SocketEvent.EVENT), update.json(), to=sid)

View File

@ -165,7 +165,7 @@ USE_EFFECT = join(
" return;",
" }}",
f" if (!{SOCKET}.current) {{{{",
f" connect({SOCKET}, {{state}}, {{set_state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {EVENT_ENDPOINT})",
f" connect({SOCKET}, {{state}}, {{set_state}}, {RESULT}, {SET_RESULT}, {ROUTER}, {EVENT_ENDPOINT}, {{transports}})",
" }}",
" const update = async () => {{",
f" if ({RESULT}.{STATE} != null) {{{{",

View File

@ -150,7 +150,10 @@ def compile_effects(state: Type[State]) -> str:
"""
state_name = state.get_name()
set_state = templates.format_state_setter(state_name)
return templates.USE_EFFECT(state=state_name, set_state=set_state)
transports = constants.Transports.POLLING_WEBSOCKET.get_transports()
return templates.USE_EFFECT(
state=state_name, set_state=set_state, transports=transports
)
def compile_render(component: Component) -> str:

View File

@ -38,3 +38,17 @@ class Config(Base):
# Additional frontend packages to install.
frontend_packages: List[str] = []
# Backend transport methods.
backend_transports: Optional[
constants.Transports
] = constants.Transports.POLLING_WEBSOCKET
# List of origins that are allowed to connect to the backend API.
cors_allowed_origins: Optional[list] = [constants.CORS_ALLOWED_ORIGINS]
# Whether credentials (cookies, authentication) are allowed in requests to the backend API.
cors_credentials: Optional[bool] = True
# The maximum size of a message when using the polling backend transport.
polling_max_http_buffer_size: Optional[int] = constants.POLLING_MAX_HTTP_BUFFER_SIZE

View File

@ -206,6 +206,36 @@ class SocketEvent(Enum):
return str(self.value)
class Transports(Enum):
"""Socket transports used by the pynecone backend API."""
POLLING_WEBSOCKET = "['polling', 'websocket']"
WEBSOCKET_POLLING = "['websocket', 'polling']"
WEBSOCKET_ONLY = "['websocket']"
POLLING_ONLY = "['polling']"
def __str__(self) -> str:
"""Get the string representation of the transports.
Returns:
The transports string.
"""
return str(self.value)
def get_transports(self) -> str:
"""Get the transports config for the backend.
Returns:
The transports config for the backend.
"""
# Import here to avoid circular imports.
from pynecone import utils
# Get the transports from the config.
config = utils.get_config()
return str(config.backend_transports)
class RouteArgType(SimpleNamespace):
"""Type of dynamic route arg extracted from URI route."""
@ -217,8 +247,11 @@ class RouteArgType(SimpleNamespace):
class RouteVar(SimpleNamespace):
"""Names of variables used in the router_data dict stored in State."""
CLIENT_IP = "ip"
CLIENT_TOKEN = "token"
HEADERS = "headers"
PATH = "pathname"
SESSION_ID = "sid"
QUERY = "query"
@ -245,3 +278,7 @@ DESCRIPTION_404 = "The page was not found"
USE_COLOR_MODE = "useColorMode"
COLOR_MODE = "colorMode"
TOGGLE_COLOR_MODE = "toggleColorMode"
# Server socket configuration variables
CORS_ALLOWED_ORIGINS = "*"
POLLING_MAX_HTTP_BUFFER_SIZE = 1000 * 1000

View File

@ -354,6 +354,30 @@ class State(Base, ABC):
"""
return self.router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
def get_sid(self) -> str:
"""Return the session ID of the client associated with this state.
Returns:
The session ID of the client.
"""
return self.router_data.get(constants.RouteVar.SESSION_ID, "")
def get_headers(self) -> Dict:
"""Return the headers of the client associated with this state.
Returns:
The headers of the client.
"""
return self.router_data.get(constants.RouteVar.HEADERS, {})
def get_client_ip(self) -> str:
"""Return the IP of the client associated with this state.
Returns:
The IP of the client.
"""
return self.router_data.get(constants.RouteVar.CLIENT_IP, "")
def get_current_page(self) -> str:
"""Obtain the path of current page from the router data.

View File

@ -36,6 +36,7 @@ redis = "^4.3.5"
httpx = "^0.23.1"
python-socketio = "^5.7.2"
psutil = "^5.9.4"
websockets = "^10.4"
[tool.poetry.dev-dependencies]
pytest = "^7.1.2"

View File

@ -627,6 +627,48 @@ def test_get_token(test_state):
assert test_state.get_token() == token
def test_get_sid(test_state):
"""Test getting session id.
Args:
test_state: A state.
"""
assert test_state.get_sid() == ""
sid = "9fpxSzPb9aFMb4wFAAAH"
test_state.router_data = {RouteVar.SESSION_ID: sid}
assert test_state.get_sid() == sid
def test_get_headers(test_state):
"""Test getting client headers.
Args:
test_state: A state.
"""
assert test_state.get_headers() == {}
headers = {"host": "localhost:8000", "connection": "keep-alive"}
test_state.router_data = {RouteVar.HEADERS: headers}
assert test_state.get_headers() == headers
def test_get_client_ip(test_state):
"""Test getting client IP.
Args:
test_state: A state.
"""
assert test_state.get_client_ip() == ""
client_ip = "127.0.0.1"
test_state.router_data = {RouteVar.CLIENT_IP: client_ip}
assert test_state.get_client_ip() == client_ip
def test_get_current_page(test_state):
assert test_state.get_current_page() == ""