Skip to content

Commit 30a31c7

Browse files
committed
fix: remove the untyped manual-IP connection path
1 parent 5eb4b9b commit 30a31c7

1 file changed

Lines changed: 24 additions & 71 deletions

File tree

src/managers/ConnectionFlowManager.ts

Lines changed: 24 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ import {
5252
} from '../utils/PrinterUtils';
5353
import { applyPerPrinterDefaults } from '../utils/printerSettingsDefaults';
5454
import { TimeoutError, withTimeout } from '../utils/ShutdownTimeout';
55-
import { IPAddressSchema } from '../utils/validation.utils';
5655
import { getLoadingManager } from './LoadingManager';
5756
import { getPrinterBackendManager } from './PrinterBackendManager';
5857
import { getPrinterContextManager } from './PrinterContextManager';
@@ -274,7 +273,7 @@ export class ConnectionFlowManager extends EventEmitter {
274273
return await this.showSavedPrintersForSelection();
275274

276275
case 'manual-ip':
277-
return await this.offerManualIPEntry();
276+
return this.manualEntryUnavailable();
278277

279278
default:
280279
return { success: false, error: 'Unknown choice' };
@@ -283,7 +282,7 @@ export class ConnectionFlowManager extends EventEmitter {
283282
// No saved printers - go directly to manual IP entry
284283
this.loadingManager.hide();
285284
console.log('No printers discovered and no saved printers - offering manual IP entry');
286-
return await this.offerManualIPEntry();
285+
return this.manualEntryUnavailable();
287286
}
288287
}
289288

@@ -406,7 +405,7 @@ export class ConnectionFlowManager extends EventEmitter {
406405
}
407406

408407
case 'manual-ip':
409-
return await this.offerManualIPEntry();
408+
return this.manualEntryUnavailable();
410409

411410
default:
412411
return { success: false, error: 'Auto-connect cancelled by user' };
@@ -820,73 +819,27 @@ export class ConnectionFlowManager extends EventEmitter {
820819
}
821820
}
822821

823-
/** Offer manual IP entry to user */
824-
private async offerManualIPEntry(): Promise<ConnectionResult> {
825-
if (!this.inputDialogHandler) {
826-
return {
827-
success: false,
828-
error: 'Manual IP entry not available - input dialog handler not set',
829-
};
830-
}
831-
832-
try {
833-
const ipAddress = await this.inputDialogHandler({
834-
title: 'Manual Printer Connection',
835-
message: 'No printers found on network. Enter printer IP address manually:',
836-
defaultValue: '',
837-
inputType: 'text',
838-
placeholder: 'e.g., 192.168.1.100',
839-
});
840-
841-
if (!ipAddress) {
842-
return { success: false, error: 'No IP address provided' };
843-
}
844-
845-
// Validate IP address format
846-
const validation = IPAddressSchema.safeParse(ipAddress.trim());
847-
if (!validation.success) {
848-
this.loadingManager.showError('Invalid IP address format', 3000);
849-
return { success: false, error: 'Invalid IP address format' };
850-
}
851-
852-
return await this.connectDirectlyToIP(validation.data);
853-
} catch (error) {
854-
const errorMessage = getConnectionErrorMessage(error);
855-
this.loadingManager.showError(`Manual connection failed: ${errorMessage}`, 4000);
856-
return { success: false, error: errorMessage };
857-
}
858-
}
859-
860-
/** Connect directly to an IP address */
861-
public async connectDirectlyToIP(ipAddress: string): Promise<ConnectionResult> {
862-
try {
863-
this.loadingManager.show({
864-
message: `Connecting to printer at ${ipAddress}...`,
865-
canCancel: false,
866-
});
867-
868-
// Create a mock discovered printer for the connection process
869-
// The actual name and serial will be determined during temporary connection
870-
const mockDiscoveredPrinter: DiscoveredPrinter = {
871-
name: `Printer at ${ipAddress}`, // Temporary name, will be updated
872-
ipAddress: ipAddress,
873-
serialNumber: '', // Will be determined during connection
874-
model: undefined, // Will be determined during connection
875-
};
876-
877-
console.log('Starting direct IP connection to:', ipAddress);
878-
879-
// Use the standard connection flow which will:
880-
// 1. Create temporary connection to get printer info
881-
// 2. Extract proper name and serial number
882-
// 3. Establish final connection with correct details
883-
return await this.connectToPrinter(mockDiscoveredPrinter);
884-
} catch (error) {
885-
const errorMessage = getConnectionErrorMessage(error);
886-
console.error('Direct IP connection failed:', error);
887-
this.loadingManager.showError(`Direct connection failed: ${errorMessage}`, 4000);
888-
return { success: false, error: errorMessage };
889-
}
822+
/**
823+
* Direct the user to the typed manual-connect form.
824+
*
825+
* This replaces `offerManualIPEntry()` / `connectDirectlyToIP(ip)`, which
826+
* built a DiscoveredPrinter with NO productId from an IP address alone. With
827+
* no product ID, `createTemporaryConnection` cannot tell that the printer is
828+
* HTTP-only, falls through to `createLegacyClient()`, and probes TCP 8899 -
829+
* which the Creator 5 series refuses outright (it runs no TCP server), so
830+
* adding one by IP failed with ECONNREFUSED. Reported against FlashForgeWebUI
831+
* in ff-5mp-hass#18.
832+
*
833+
* The browser's "Add Printer" form requires a printer type and sends the
834+
* matching product ID, so it identifies an HTTP-only model before any socket
835+
* is opened. That is the only manual path that is safe to offer.
836+
*/
837+
private manualEntryUnavailable(): ConnectionResult {
838+
const message =
839+
'Use the "Add Printer" form to add a printer by IP - it asks for the printer type, ' +
840+
'which is required to connect models that have no legacy TCP service (Creator 5 / 5 Pro).';
841+
this.loadingManager.showError(message, 5000);
842+
return { success: false, error: message };
890843
}
891844

892845
/** Show saved printers for manual selection */

0 commit comments

Comments
 (0)