feat: enable Windows app internet access and improve server discovery

This commit is contained in:
ssbg04 committed 2026-07-26 13:19:59 +08:00
1 parent 443a930b57
commit aebfeca342
5 files changed
+52 -19

No files matched your search

+3 -3
View File
@@ -54,11 +54,11 @@ app.use('/api/ocr', ocrRoutes);
app.use('/api/notifications', notificationRoutes);
app.use('/api/backup', backupRoutes);
app.get('/', (req, res) => {
app.get(['/', '/api'], (req, res) => {
res.set('X-TIS-RMS', 'true');
res.json({ message: 'TIS RMS API is running' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server running on port ${PORT} (0.0.0.0)`);
});
+2 -2
View File
@@ -2,8 +2,8 @@ class ApiConstants {
static const int port = 18484;
// Runtime-mutable base URL — set by ServerDiscoveryService before first use.
// Default: localhost for Windows desktop, Android will discover via LAN scan.
static String _baseUrl = 'http://127.0.0.1:$port/api';
// Default: remote internet/configured server IP or domain.
static String _baseUrl = 'http://198.252.107.197:$port/api';
static String get baseUrl => _baseUrl;
@@ -33,9 +33,12 @@ class ServerDiscoveryService {
static Future<bool> ping(String baseUrl) async {
try {
final rootUrl = baseUrl
.replaceAll(RegExp(r'/+$'), '')
.replaceAll(RegExp(r'/api$'), '');
final dio = Dio(
BaseOptions(
baseUrl: baseUrl,
baseUrl: rootUrl,
connectTimeout: _pingTimeout,
receiveTimeout: _pingTimeout,
),
@@ -458,7 +458,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> with SingleTickerProv
controller: controller,
decoration: InputDecoration(
labelText: 'Server URL',
hintText: 'http://192.168.1.x:18484/api',
hintText: 'http://198.252.107.197:18484/api',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
@@ -467,6 +467,16 @@ class _LoginScreenState extends ConsumerState<LoginScreen> with SingleTickerProv
],
),
actions: [
TextButton(
onPressed: () async {
const defaultUrl = 'http://198.252.107.197:18484/api';
ApiConstants.setBaseUrl(defaultUrl);
await ServerDiscoveryService.save(ApiConstants.baseUrl);
if (mounted) setState(() {});
Navigator.pop(ctx);
},
child: const Text('Reset to Default'),
),
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('Cancel'),
@@ -83,13 +83,7 @@ class _SplashScreenState extends ConsumerState<SplashScreen>
// ── Server resolution logic ────────────────────────────────────────────────
Future<void> _resolveServer() async {
// Windows: always local, no need to scan
if (!kIsWeb && Platform.isWindows) {
ApiConstants.setBaseUrl('http://127.0.0.1:${ApiConstants.port}');
return;
}
// Android / other: check saved URL first
// 1. Check saved URL first (all platforms including Windows)
final saved = await ServerDiscoveryService.getSaved();
if (saved != null) {
setState(() => _statusText = 'Connecting to saved server…');
@@ -98,11 +92,35 @@ class _SplashScreenState extends ConsumerState<SplashScreen>
ApiConstants.setBaseUrl(saved);
return;
}
// Saved server is gone — clear it and scan
// Saved server is unreachable — clear it and continue discovery
await ServerDiscoveryService.clear();
}
// Run subnet scan
// 2. Check default configured internet/remote server in ApiConstants
final defaultRoot =
ApiConstants.baseUrl.replaceAll(RegExp(r'/api/?$'), '');
setState(() => _statusText = 'Connecting to remote server…');
final defaultAlive = await ServerDiscoveryService.ping(defaultRoot);
if (defaultAlive) {
await ServerDiscoveryService.save(defaultRoot);
ApiConstants.setBaseUrl(defaultRoot);
return;
}
// 3. On desktop platforms, check localhost as a fallback (if running local backend)
if (!kIsWeb &&
(Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
const localUrl = 'http://127.0.0.1:${ApiConstants.port}';
setState(() => _statusText = 'Checking local server…');
final localAlive = await ServerDiscoveryService.ping(localUrl);
if (localAlive) {
await ServerDiscoveryService.save(localUrl);
ApiConstants.setBaseUrl(localUrl);
return;
}
}
// 4. Run subnet scan (or prompt for manual entry if nothing found)
await _runScan();
}
@@ -193,8 +211,8 @@ class _SplashScreenState extends ConsumerState<SplashScreen>
controller: controller,
keyboardType: TextInputType.url,
decoration: InputDecoration(
labelText: 'Server IP Address',
hintText: '192.168.1.x',
labelText: 'Server IP / Domain',
hintText: '198.252.107.197 or domain.com',
prefixIcon: const Icon(Icons.dns_outlined),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
@@ -227,7 +245,9 @@ class _SplashScreenState extends ConsumerState<SplashScreen>
if (ip.isNotEmpty) {
final url = ip.startsWith('http')
? ip
: 'http://$ip:${ApiConstants.port}';
: ip.contains(':')
? 'http://$ip'
: 'http://$ip:${ApiConstants.port}';
ServerDiscoveryService.save(url);
ApiConstants.setBaseUrl(url);
}