Yield with uploads (#1339)
This commit is contained in:
parent
3f151f054d
commit
ca11b82432
@ -323,21 +323,26 @@ export const uploadFiles = async (state, setResult, handler) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send the file to the server.
|
// Send the file to the server.
|
||||||
await axios.post(UPLOADURL, formdata, headers).then((response) => {
|
await axios.post(UPLOADURL, formdata, headers)
|
||||||
// Apply the delta and set the result.
|
.then(() => { return true; })
|
||||||
const update = response.data;
|
.catch(
|
||||||
applyDelta(state, update.delta);
|
error => {
|
||||||
|
if (error.response) {
|
||||||
// Set processing to false and return.
|
// The request was made and the server responded with a status code
|
||||||
setResult({
|
// that falls out of the range of 2xx
|
||||||
state: state,
|
console.log(error.response.data);
|
||||||
events: update.events,
|
} else if (error.request) {
|
||||||
final: true,
|
// The request was made but no response was received
|
||||||
processing: false,
|
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||||
});
|
// http.ClientRequest in node.js
|
||||||
});
|
console.log(error.request);
|
||||||
|
} else {
|
||||||
return true;
|
// Something happened in setting up the request that triggered an Error
|
||||||
|
console.log(error.message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,6 +88,9 @@ class App(Base):
|
|||||||
# The component to render if there is a connection error to the server.
|
# The component to render if there is a connection error to the server.
|
||||||
connect_error_component: Optional[Component] = None
|
connect_error_component: Optional[Component] = None
|
||||||
|
|
||||||
|
# The async server name space
|
||||||
|
event_namespace: Optional[AsyncNamespace] = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""Initialize the app.
|
"""Initialize the app.
|
||||||
|
|
||||||
@ -127,11 +130,10 @@ class App(Base):
|
|||||||
self.socket_app = ASGIApp(self.sio, socketio_path="")
|
self.socket_app = ASGIApp(self.sio, socketio_path="")
|
||||||
|
|
||||||
# Create the event namespace and attach the main app. Not related to any paths.
|
# Create the event namespace and attach the main app. Not related to any paths.
|
||||||
event_namespace = EventNamespace("/event", self)
|
self.event_namespace = EventNamespace("/event", self)
|
||||||
|
|
||||||
# Register the event namespace with the socket.
|
# Register the event namespace with the socket.
|
||||||
self.sio.register_namespace(event_namespace)
|
self.sio.register_namespace(self.event_namespace)
|
||||||
|
|
||||||
# Mount the socket app with the API.
|
# Mount the socket app with the API.
|
||||||
self.api.mount(str(constants.Endpoint.EVENT), self.socket_app)
|
self.api.mount(str(constants.Endpoint.EVENT), self.socket_app)
|
||||||
|
|
||||||
@ -592,9 +594,6 @@ def upload(app: App):
|
|||||||
Args:
|
Args:
|
||||||
files: The file(s) to upload.
|
files: The file(s) to upload.
|
||||||
|
|
||||||
Returns:
|
|
||||||
The state update after processing the event.
|
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: if there are no args with supported annotation.
|
ValueError: if there are no args with supported annotation.
|
||||||
"""
|
"""
|
||||||
@ -603,10 +602,10 @@ def upload(app: App):
|
|||||||
for file in files:
|
for file in files:
|
||||||
assert file.filename is not None
|
assert file.filename is not None
|
||||||
file.filename = file.filename.split(":")[-1]
|
file.filename = file.filename.split(":")[-1]
|
||||||
|
|
||||||
# Get the state for the session.
|
# Get the state for the session.
|
||||||
state = app.state_manager.get_state(token)
|
state = app.state_manager.get_state(token)
|
||||||
|
# get the current session ID
|
||||||
|
sid = state.get_sid()
|
||||||
# get the current state(parent state/substate)
|
# get the current state(parent state/substate)
|
||||||
path = handler.split(".")[:-1]
|
path = handler.split(".")[:-1]
|
||||||
current_state = state.get_substate(path)
|
current_state = state.get_substate(path)
|
||||||
@ -636,12 +635,17 @@ def upload(app: App):
|
|||||||
name=handler,
|
name=handler,
|
||||||
payload={handler_upload_param[0]: files},
|
payload={handler_upload_param[0]: files},
|
||||||
)
|
)
|
||||||
# TODO: refactor this to handle yields.
|
async for update in state._process(event):
|
||||||
update = await state._process(event).__anext__()
|
# Postprocess the event.
|
||||||
|
update = await app.postprocess(state, event, update)
|
||||||
|
# Send update to client
|
||||||
|
await asyncio.create_task(
|
||||||
|
app.event_namespace.emit( # type: ignore
|
||||||
|
str(constants.SocketEvent.EVENT), update.json(), to=sid
|
||||||
|
)
|
||||||
|
)
|
||||||
# Set the state for the session.
|
# Set the state for the session.
|
||||||
app.state_manager.set_state(event.token, state)
|
app.state_manager.set_state(event.token, state)
|
||||||
return update
|
|
||||||
|
|
||||||
return upload_file
|
return upload_file
|
||||||
|
|
||||||
|
@ -602,7 +602,7 @@ async def test_dict_mutation_detection__plain_list(
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"fixture, expected",
|
"fixture, delta",
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
"upload_state",
|
"upload_state",
|
||||||
@ -626,22 +626,23 @@ async def test_dict_mutation_detection__plain_list(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_upload_file(fixture, request, expected):
|
async def test_upload_file(fixture, request, delta):
|
||||||
"""Test that file upload works correctly.
|
"""Test that file upload works correctly.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
fixture: The state.
|
fixture: The state.
|
||||||
request: Fixture request.
|
request: Fixture request.
|
||||||
expected: Expected delta
|
delta: Expected delta
|
||||||
"""
|
"""
|
||||||
|
app = App(state=request.getfixturevalue(fixture))
|
||||||
|
app.event_namespace.emit = AsyncMock() # type: ignore
|
||||||
|
current_state = app.state_manager.get_state("token")
|
||||||
data = b"This is binary data"
|
data = b"This is binary data"
|
||||||
|
|
||||||
# Create a binary IO object and write data to it
|
# Create a binary IO object and write data to it
|
||||||
bio = io.BytesIO()
|
bio = io.BytesIO()
|
||||||
bio.write(data)
|
bio.write(data)
|
||||||
|
|
||||||
app = App(state=request.getfixturevalue(fixture))
|
|
||||||
|
|
||||||
file1 = UploadFile(
|
file1 = UploadFile(
|
||||||
filename="token:file_upload_state.multi_handle_upload:True:image1.jpg",
|
filename="token:file_upload_state.multi_handle_upload:True:image1.jpg",
|
||||||
file=bio,
|
file=bio,
|
||||||
@ -650,10 +651,17 @@ async def test_upload_file(fixture, request, expected):
|
|||||||
filename="token:file_upload_state.multi_handle_upload:True:image2.jpg",
|
filename="token:file_upload_state.multi_handle_upload:True:image2.jpg",
|
||||||
file=bio,
|
file=bio,
|
||||||
)
|
)
|
||||||
fn = upload(app)
|
upload_fn = upload(app)
|
||||||
result = await fn([file1, file2]) # type: ignore
|
await upload_fn([file1, file2])
|
||||||
assert isinstance(result, StateUpdate)
|
state_update = StateUpdate(delta=delta, events=[], final=True)
|
||||||
assert result.delta == expected
|
|
||||||
|
app.event_namespace.emit.assert_called_with( # type: ignore
|
||||||
|
"event", state_update.json(), to=current_state.get_sid()
|
||||||
|
)
|
||||||
|
assert app.state_manager.get_state("token").dict()["img_list"] == [
|
||||||
|
"image1.jpg",
|
||||||
|
"image2.jpg",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
Loading…
Reference in New Issue
Block a user