feat: add external ROS communication toggle for local workspaces

This commit is contained in:
2026-09-16 15:35:15 +09:00
parent 76a87fc20d
commit 1d959e2c51
9 changed files with 25 additions and 8 deletions
+4 -3
View File
@@ -260,6 +260,7 @@ type RemoteWorkspaceTarget = {
type RosNetworkConfig = {
enabled?: boolean | null
allowExternal?: boolean
peer?: RemoteWorkspaceTarget | null
}
@@ -3791,7 +3792,7 @@ async function startVisualizationBridge(
const requestedRosDomainId = String(rosDomainId ?? process.env.ROS_DOMAIN_ID ?? '0').trim() || '0'
const requestedRosNetworkKey = rosNetworkEnabled(rosNetwork)
? `peer:${rosNetwork?.peer?.host?.trim() ?? ''}`
: 'local'
: rosNetwork?.allowExternal === true ? 'lan' : 'local'
const otherContainerNames = (['autoware', 'nav2', 'slam'] as VisualizationStack[])
.filter((item) => item !== stack)
.map(visualizationBridgeContainerName)
@@ -3869,7 +3870,7 @@ async function startVisualizationBridge(
'-e',
`ROS_DOMAIN_ID=${requestedRosDomainId}`,
'-e',
`ROS_LOCALHOST_ONLY=${rosNetworkEnabled(rosNetwork) ? '0' : '1'}`,
`ROS_LOCALHOST_ONLY=${rosNetworkEnabled(rosNetwork) || rosNetwork?.allowExternal === true ? '0' : '1'}`,
'-e',
`AUTONOMY_STUDIO_ROS_NETWORK=${requestedRosNetworkKey}`,
'-e',
@@ -5062,7 +5063,7 @@ async function startWorkspaceModule(
],
undefined,
{
ROS_LOCALHOST_ONLY: rosNetworkEnabled(rosNetwork) ? '0' : '1',
ROS_LOCALHOST_ONLY: rosNetworkEnabled(rosNetwork) || rosNetwork?.allowExternal === true ? '0' : '1',
...(fastDdsConfigPath ? { FASTDDS_CONFIG_PATH: fastDdsConfigPath } : {}),
},
30000
+1
View File
@@ -54,6 +54,7 @@ type ModuleInstallOptions = {
type RosNetworkConfig = {
enabled?: boolean | null
allowExternal?: boolean
peer?: RemoteWorkspaceTarget | null
}
+7 -4
View File
@@ -1000,9 +1000,10 @@ function LocalPcWorkspaceMockup({
workspaceRoot: remoteRuntimeRoot,
} : null
const rosNetworkConfig = useMemo<RosNetworkConfig | null>(() => {
if (!rosWorkspaceLinked) return null
const localNetwork = !remoteWorkspace ? { enabled: false, allowExternal: sourceSettings.allowExternalRos === true } : null
if (!rosWorkspaceLinked) return localNetwork
if (remoteWorkspace) return { enabled: true }
if (!linkedPlatform) return null
if (!linkedPlatform) return localNetwork
const linkedDefaults = normalizeStudioSourceSettings({
...(linkedPlatform.sourceSettings ?? {}),
@@ -1013,7 +1014,7 @@ function LocalPcWorkspaceMockup({
const peerHost = parseHostFromUrl(readNestedString(linkedProfile?.config, ['agent', 'url']))
?? parseHostFromUrl(readNestedString(linkedProfile?.config, ['bridge', 'env', 'BRIDGE_HTTP_URL']))
?? parseHostFromUrl(linkedDefaults.agentUrl ?? null)
if (!peerHost) return null
if (!peerHost) return localNetwork
const peerPort = Number(linkedDefaults.sshPort ?? 22)
return {
@@ -1024,7 +1025,7 @@ function LocalPcWorkspaceMockup({
port: Number.isFinite(peerPort) && peerPort > 0 ? peerPort : 22,
},
}
}, [linkedPlatform, remoteWorkspace, rosWorkspaceLinked, weekNumber])
}, [linkedPlatform, remoteWorkspace, rosWorkspaceLinked, weekNumber, sourceSettings.allowExternalRos])
const visualizationBridgeLocation = (
remoteWorkspace ? localWorkspaceSettings.visualizationBridgeLocation : sourceSettings.visualizationBridgeLocation
) === 'platform' && rosWorkspaceLinked
@@ -2449,6 +2450,7 @@ function LocalPcWorkspaceMockup({
giteaBaseUrl: sourceSettings.giteaBaseUrl,
giteaOwner: sourceSettings.giteaOwner,
gpuEnabled: sourceSettingsDraft.gpuEnabled,
allowExternalRos: !remoteWorkspace && sourceSettingsDraft.allowExternalRos === true,
editorWordWrap: sourceSettingsDraft.editorWordWrap,
editorFontSize: sourceSettingsDraft.editorFontSize,
editorTabSize: sourceSettingsDraft.editorTabSize,
@@ -2475,6 +2477,7 @@ function LocalPcWorkspaceMockup({
giteaBaseUrl: sourceSettings.giteaBaseUrl,
giteaOwner: sourceSettings.giteaOwner,
gpuEnabled: settings.gpuEnabled,
allowExternalRos: !remoteWorkspace && settings.allowExternalRos === true,
editorWordWrap: settings.editorWordWrap,
editorFontSize: settings.editorFontSize,
editorTabSize: settings.editorTabSize,
+1
View File
@@ -34,6 +34,7 @@ type ModuleInstallOptions = {
type RosNetworkConfig = {
enabled?: boolean | null
allowExternal?: boolean
peer?: RemoteWorkspaceTarget | null
}
@@ -8,6 +8,7 @@ export type StudioSourceSettings = {
editorTabSize: number
editorMinimap: boolean
rosDomainId: string
allowExternalRos?: boolean
rosLinkedPlatformId?: string | null
visualizationBridgeLocation?: 'local' | 'platform'
agentUrl?: string | null
@@ -97,6 +97,13 @@ function WorkspaceSettingsView({
dark={dark}
/>
</div>
<StudioSettingsSwitch
label="외부 ROS 통신"
description="같은 네트워크의 기체와 통신을 허용합니다. 사용자별 ROS Domain ID를 구분하고, 변경 후 모듈과 시각화를 재실행하세요. 플랫폼 연동 통신은 별도 설정을 따릅니다."
checked={sourceSettingsDraft.allowExternalRos === true}
onChange={(checked) => onUpdateSourceSetting('allowExternalRos', checked)}
dark={dark}
/>
<StudioSettingsSwitch
label="GPU 가속"
description="ON이면 Docker 실행 시 NVIDIA GPU를 사용합니다."
@@ -11,6 +11,7 @@ export const defaultStudioSourceSettings: StudioSourceSettings = {
editorTabSize: 4,
editorMinimap: true,
rosDomainId: '77',
allowExternalRos: false,
rosLinkedPlatformId: null,
visualizationBridgeLocation: 'local',
}
@@ -53,6 +54,7 @@ export function normalizeStudioSourceSettings(settings?: Partial<StudioSourceSet
giteaBaseUrl: (settings?.giteaBaseUrl || defaultStudioSourceSettings.giteaBaseUrl).replace(/\/+$/, ''),
giteaOwner: giteaOwner === 'students' ? defaultStudioSourceSettings.giteaOwner : giteaOwner,
gpuEnabled: Boolean(settings?.gpuEnabled),
allowExternalRos: settings?.allowExternalRos === true,
editorWordWrap: settings?.editorWordWrap ?? defaultStudioSourceSettings.editorWordWrap,
editorFontSize: Number.isFinite(requestedEditorFontSize)
? Math.min(16, Math.max(12, Math.round(requestedEditorFontSize)))
@@ -47,5 +47,6 @@ export type RuntimeImageArtifact = {
export type RosNetworkConfig = {
enabled?: boolean
allowExternal?: boolean
peer?: RemoteWorkspaceTarget | null
}