Skip to content

Commit

Permalink
Send message to parent (#7522)
Browse files Browse the repository at this point in the history
Extension of host configuration endpoint - setting to enable/disable custom string messages from app to host
  • Loading branch information
mayagbarnes committed Oct 18, 2023
1 parent 397e6e6 commit ec2eb2b
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 3 deletions.
34 changes: 34 additions & 0 deletions frontend/app/src/App.test.tsx
Expand Up @@ -45,6 +45,7 @@ import {
PageInfo,
PageNotFound,
PagesChanged,
ParentMessage,
mockTheme,
HOST_COMM_VERSION,
} from "@streamlit/lib"
Expand Down Expand Up @@ -1735,4 +1736,37 @@ describe("handles HostCommunication messaging", () => {

expect(wrapper.find("DeployButton")).toHaveLength(0)
})

it("does not relay custom parent messages by default", () => {
const logErrorSpy = jest
.spyOn(global.console, "error")
.mockImplementation(() => {})

const msg = new ForwardMsg()
msg.parentMessage = new ParentMessage({ message: "random string" })
instance.handleMessage(msg)

expect(logErrorSpy).toHaveBeenCalled()
expect(logErrorSpy.mock.calls[0][0]).toEqual(
"Sending messages to the host is disabled in line with the platform policy."
)
})

it("relays custom parent messages when enabled", () => {
instance.setState({ appConfig: { enableCustomParentMessages: true } })
const sendMessageFunc = jest.spyOn(
// @ts-expect-error
instance.hostCommunicationMgr,
"sendMessageToHost"
)

const msg = new ForwardMsg()
msg.parentMessage = new ParentMessage({ message: "random string" })
instance.handleMessage(msg)

expect(sendMessageFunc).toHaveBeenCalledWith({
type: "CUSTOM_PARENT_MESSAGE",
message: "random string",
})
})
})
28 changes: 26 additions & 2 deletions frontend/app/src/App.tsx
Expand Up @@ -92,6 +92,7 @@ import {
PageNotFound,
PageProfile,
PagesChanged,
ParentMessage,
SessionEvent,
SessionStatus,
WidgetStates,
Expand Down Expand Up @@ -386,8 +387,16 @@ export class App extends PureComponent<Props, State> {
claimHostAuthToken: this.hostCommunicationMgr.claimAuthToken,
resetHostAuthToken: this.hostCommunicationMgr.resetAuthToken,
onHostConfigResp: (response: IHostConfigResponse) => {
const { allowedOrigins, useExternalAuthToken } = response
const appConfig: AppConfig = { allowedOrigins, useExternalAuthToken }
const {
allowedOrigins,
useExternalAuthToken,
enableCustomParentMessages,
} = response
const appConfig: AppConfig = {
allowedOrigins,
useExternalAuthToken,
enableCustomParentMessages,
}
const libConfig: LibConfig = {} // TODO(lukasmasuch): We don't have any libConfig yet:

// Set the allowed origins configuration for the host communication:
Expand Down Expand Up @@ -552,6 +561,19 @@ export class App extends PureComponent<Props, State> {
})
}

handleCustomParentMessage = (parentMessage: ParentMessage): void => {
if (this.state.appConfig.enableCustomParentMessages) {
this.hostCommunicationMgr.sendMessageToHost({
type: "CUSTOM_PARENT_MESSAGE",
message: parentMessage.message,
})
} else {
logError(
"Sending messages to the host is disabled in line with the platform policy."
)
}
}

/**
* Callback when we get a message from the server.
*/
Expand Down Expand Up @@ -595,6 +617,8 @@ export class App extends PureComponent<Props, State> {
this.handlePageProfileMsg(pageProfile),
fileUrlsResponse: (fileURLsResponse: FileURLsResponse) =>
this.uploadClient.onFileURLsResponse(fileURLsResponse),
parentMessage: (parentMessage: ParentMessage) =>
this.handleCustomParentMessage(parentMessage),
})
} catch (e) {
const err = ensureError(e)
Expand Down
8 changes: 8 additions & 0 deletions frontend/lib/src/hostComm/types.ts
Expand Up @@ -156,6 +156,10 @@ export type IGuestToHostMessage =
type: "SCRIPT_RUN_STATE_CHANGED"
scriptRunState: ScriptRunState
}
| {
type: "CUSTOM_PARENT_MESSAGE"
message: string
}

export type VersionedMessage<Message> = {
stCommVersion: number
Expand Down Expand Up @@ -183,6 +187,10 @@ export type AppConfig = {
* with the Streamlit server.
*/
useExternalAuthToken?: boolean
/**
* Enables custom string messages to be sent to the host
*/
enableCustomParentMessages?: boolean
}

/**
Expand Down
31 changes: 31 additions & 0 deletions lib/streamlit/platform.py
@@ -0,0 +1,31 @@
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Platform module."""

from streamlit.proto.ForwardMsg_pb2 import ForwardMsg
from streamlit.runtime.scriptrunner import get_script_run_ctx


def post_parent_message(message: str) -> None:
"""
Sends a string message to the parent window (when host configuration allows).
"""
ctx = get_script_run_ctx()
if ctx is None:
return

fwd_msg = ForwardMsg()
fwd_msg.parent_message.message = message
ctx.enqueue(fwd_msg)
2 changes: 2 additions & 0 deletions lib/streamlit/web/server/routes.py
Expand Up @@ -202,6 +202,8 @@ async def get(self) -> None:
{
"allowedOrigins": self._allowed_origins,
"useExternalAuthToken": False,
# Default host configuration settings.
"enableCustomParentMessages": False,
}
)
self.set_status(200)
Expand Down
28 changes: 28 additions & 0 deletions lib/tests/streamlit/platform_test.py
@@ -0,0 +1,28 @@
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from parameterized import parameterized

from streamlit.platform import post_parent_message
from tests.delta_generator_test_case import DeltaGeneratorTestCase


class PlatformTest(DeltaGeneratorTestCase):
"""Tests the platform module functions"""

@parameterized.expand(["Hello", '{"name":"foo", "type":"bar"}'])
def test_post_parent_message(self, message: str):
post_parent_message(message)
c = self.get_message_from_queue().parent_message
self.assertEqual(c.message, message)
2 changes: 2 additions & 0 deletions lib/tests/streamlit/web/server/routes_test.py
Expand Up @@ -191,6 +191,8 @@ def test_allowed_message_origins(self):
{
"allowedOrigins": _DEFAULT_ALLOWED_MESSAGE_ORIGINS,
"useExternalAuthToken": False,
# Default host configuration settings:
"enableCustomParentMessages": False,
},
response_body,
)
Expand Down
6 changes: 5 additions & 1 deletion proto/streamlit/proto/ForwardMsg.proto
Expand Up @@ -25,6 +25,7 @@ import "streamlit/proto/PageInfo.proto";
import "streamlit/proto/PageProfile.proto";
import "streamlit/proto/PageNotFound.proto";
import "streamlit/proto/PagesChanged.proto";
import "streamlit/proto/ParentMessage.proto";
import "streamlit/proto/SessionEvent.proto";
import "streamlit/proto/SessionStatus.proto";

Expand Down Expand Up @@ -68,6 +69,9 @@ message ForwardMsg {
PagesChanged pages_changed = 16;
FileURLsResponse file_urls_response = 19;

// Platform - message to host
ParentMessage parent_message = 20;

// A reference to a ForwardMsg that has already been delivered.
// The client should substitute the message with the given hash
// for this one. If the client does not have the referenced message
Expand All @@ -81,7 +85,7 @@ message ForwardMsg {
string debug_last_backmsg_id = 17;

reserved 7, 8;
// Next: 20
// Next: 21
}

// ForwardMsgMetadata contains all data that does _not_ get hashed (or cached)
Expand Down
22 changes: 22 additions & 0 deletions proto/streamlit/proto/ParentMessage.proto
@@ -0,0 +1,22 @@
/**!
* Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

syntax = "proto3";

message ParentMessage {
// Message to send to the host.
string message = 1;
}

0 comments on commit ec2eb2b

Please sign in to comment.