Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions .cursor/commands/solve_issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ Check GitHub issue by running `gh issue view` command and analyze, solve the iss
- Read codebase and understand why we have to solve the issue.
- Analyze way to solve the issue by reading files, codes.

3. ** Solve the issue**
3. ** Checkout branch for the fix**
- Checkout new branch with issue number

4. ** Solve the issue**
- Modify the code and solve the issue
- check if it is solved. Run compile check or unit tests if needed.
- If it was complicated issue, make a comment on the issue/PR for documentation.
- If it was complicated issue, make a comment on the issue/PR for documentation.

5. ** Confirm the issue is solved**
- Make sure the issue is solved
- Check the codes and process with integration test

6. ** Commit and push the changes**
- commit, push and publish branch.
- Open Pull Request using gh cli.
- Open the PR with web browser and ask user to review it.
18 changes: 13 additions & 5 deletions app/src-tauri/src/network_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct VmixScanResult {
pub is_vmix: bool,
pub response_time: u64,
pub error_message: Option<String>,
pub preset: Option<String>,
}

pub fn get_network_interfaces() -> Result<Vec<NetworkInterface>> {
Expand Down Expand Up @@ -77,6 +78,7 @@ pub async fn scan_network_for_vmix(interface_name: String, app_state: &crate::st
}

let subnet = target_interface.subnet.clone();
let interface_ip = target_interface.ip_address.clone();
let port = 8088;

// 既に接続されているIPアドレスのリストを取得
Expand Down Expand Up @@ -104,7 +106,7 @@ pub async fn scan_network_for_vmix(interface_name: String, app_state: &crate::st
let mut tasks = vec![];
let mut results = Vec::new();

// 1から254までのIPアドレスをスキャン(既に接続されているIPは除外
// 1から254までのIPアドレスをスキャン(既に接続されているIPとローカルホストは除外
for host in 1..=254 {
let ip_str = format!("{}.{}", subnet, host);

Expand All @@ -113,6 +115,11 @@ pub async fn scan_network_for_vmix(interface_name: String, app_state: &crate::st
continue;
}

// ネットワークインターフェースのIPアドレス(localhost)は除外
if ip_str == interface_ip {
continue;
}

let ip: IpAddr = ip_str.parse::<Ipv4Addr>()?.into();
let addr = SocketAddr::new(ip, port);
let semaphore_clone = semaphore.clone();
Expand Down Expand Up @@ -140,23 +147,24 @@ pub async fn scan_network_for_vmix(interface_name: String, app_state: &crate::st
async fn check_vmix_port(addr: SocketAddr) -> Option<VmixScanResult> {
let start_time = std::time::Instant::now();

// vMix HTTP APIを使用してvMixの存在を確認
// vMix HTTP APIを使用してvMixの存在を確認し、プリセット名も取得
match check_vmix_http_api(addr).await {
Ok(_) => {
Ok(vmix_data) => {
let response_time = start_time.elapsed().as_millis() as u64;
Some(VmixScanResult {
ip_address: addr.ip().to_string(),
port: addr.port(),
is_vmix: true,
response_time,
error_message: None,
preset: vmix_data.preset,
})
}
Err(_e) => None,
}
}

async fn check_vmix_http_api(addr: SocketAddr) -> Result<()> {
async fn check_vmix_http_api(addr: SocketAddr) -> Result<crate::types::VmixXml> {
let host = addr.ip().to_string();
let port = addr.port();

Expand All @@ -165,7 +173,7 @@ async fn check_vmix_http_api(addr: SocketAddr) -> Result<()> {

// 短いタイムアウトでXMLを取得・パースできた場合のみ成功とみなす
match tokio::time::timeout(Duration::from_secs(1), client.get_vmix_data()).await {
Ok(Ok(_xml)) => Ok(()),
Ok(Ok(xml)) => Ok(xml),
Ok(Err(e)) => Err(anyhow::anyhow!("HTTP API XML error: {}", e)),
Err(_) => Err(anyhow::anyhow!("HTTP API timeout")),
}
Expand Down
19 changes: 7 additions & 12 deletions app/src/pages/Connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,16 @@ const Connections: React.FC = () => {
};

const handleConnectFromScan = async (ipAddress: string) => {
// Close scan dialog immediately for better UX
setScanDialogOpen(false);

// Don't close dialog - allow connecting to multiple vMix instances
// Add to background connections set
setBackgroundConnections(prev => new Set([...prev, ipAddress]));

try {
await connectVMix(ipAddress, 8088, 'Http');

// Refresh connections to update the UI
await refreshConnections();

// Add success notification
setConnectionNotifications(prev => [...prev, {
host: ipAddress,
Expand Down Expand Up @@ -881,8 +882,7 @@ const Connections: React.FC = () => {
<TableHead>
<TableRow>
<TableCell>IP Address</TableCell>
<TableCell>Port</TableCell>
<TableCell>Status</TableCell>
<TableCell>Preset</TableCell>
<TableCell>Response Time</TableCell>
<TableCell>Action</TableCell>
</TableRow>
Expand All @@ -891,13 +891,8 @@ const Connections: React.FC = () => {
{scanResults.map((result, index) => (
<TableRow key={index}>
<TableCell>{result.ip_address}</TableCell>
<TableCell>{result.port}</TableCell>
<TableCell>
<Chip
label={result.is_vmix ? 'vMix Found' : 'HTTP Service'}
color={result.is_vmix ? 'success' : 'default'}
size="small"
/>
<Typography variant="body2">{result.preset || '-'}</Typography>
</TableCell>
<TableCell>{result.response_time}ms</TableCell>
<TableCell>
Expand Down Expand Up @@ -930,7 +925,7 @@ const Connections: React.FC = () => {
disabled={!selectedInterface || isScanning}
startIcon={isScanning ? <CircularProgress size={16} /> : <SearchIcon />}
>
{isScanning ? 'Scanning...' : 'Start Scan'}
{isScanning ? 'Scanning...' : (scanResults.length > 0 ? 'Rescan' : 'Start Scan')}
</Button>
</DialogActions>
</Dialog>
Expand Down
1 change: 1 addition & 0 deletions app/src/services/networkScannerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface VmixScanResult {
is_vmix: boolean;
response_time: number;
error_message?: string;
preset?: string;
}

export class NetworkScannerService {
Expand Down