2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

Refactor API connection code

This commit is contained in:
Oliver Walters 2021-02-09 14:16:31 +11:00
parent 1c0b469020
commit 7373805ea7
3 changed files with 177 additions and 141 deletions

View File

@ -109,13 +109,11 @@ class InvenTreeAPI {
String makeUrl(String endpoint) => _makeUrl(endpoint); String makeUrl(String endpoint) => _makeUrl(endpoint);
UserProfile _profile; UserProfile profile;
// Authentication token (initially empty, must be requested) // Authentication token (initially empty, must be requested)
String _token = ""; String _token = "";
bool isConnected() => _token.isNotEmpty;
/* /*
* Check server connection and display messages if not connected. * Check server connection and display messages if not connected.
* Useful as a precursor check before performing operations. * Useful as a precursor check before performing operations.
@ -154,8 +152,14 @@ class InvenTreeAPI {
// Connection status flag - set once connection has been validated // Connection status flag - set once connection has been validated
bool _connected = false; bool _connected = false;
bool get connected { bool _connecting = true;
return _connected && baseUrl.isNotEmpty && _token.isNotEmpty;
bool isConnected() {
return profile != null && _connected && baseUrl.isNotEmpty && _token.isNotEmpty;
}
bool isConnecting() {
return !isConnected() && _connecting;
} }
// Ensure we only ever create a single instance of the API class // Ensure we only ever create a single instance of the API class
@ -167,35 +171,15 @@ class InvenTreeAPI {
InvenTreeAPI._internal(); InvenTreeAPI._internal();
Future<bool> connect(BuildContext context) async { Future<bool> _connect(BuildContext context) async {
_profile = await UserProfileDBManager().getSelectedProfile();
if (_profile == null) {
await showErrorDialog(
context,
"Select Profile",
"User profile not selected"
);
return false;
}
return connectToServer(context);
}
Future<bool> connectToServer(BuildContext context) async {
/* Address is the base address for the InvenTree server, /* Address is the base address for the InvenTree server,
* e.g. http://127.0.0.1:8000 * e.g. http://127.0.0.1:8000
*/ */
if (_profile == null) return false; String address = profile.server.trim();
String username = profile.username.trim();
String errorMessage = ""; String password = profile.password.trim();
String address = _profile.server.trim();
String username = _profile.username.trim();
String password = _profile.password.trim();
if (address.isEmpty || username.isEmpty || password.isEmpty) { if (address.isEmpty || username.isEmpty || password.isEmpty) {
await showErrorDialog( await showErrorDialog(
@ -220,19 +204,18 @@ class InvenTreeAPI {
*/ */
_BASE_URL = address; _BASE_URL = address;
_connected = false;
print("Connecting to " + apiUrl + " -> " + username + ":" + password); print("Connecting to ${apiUrl} -> ${username}:${password}");
var response = await get("").timeout(Duration(seconds: 5)).catchError((error) { var response = await get("").timeout(Duration(seconds: 5)).catchError((error) {
print("Error connecting to server: ${error.toString()}"); print("Error connecting to server: ${error.toString()}");
if (error is SocketException) { if (error is SocketException) {
errorMessage = "Could not connect to server"; showServerError(context, "Connection Refused");
return null; return null;
} else if (error is TimeoutException) { } else if (error is TimeoutException) {
errorMessage = "Server timeout"; showTimeoutDialog(context);
return null; return null;
} else { } else {
// Unknown error type - re-throw the error and Sentry will catch it // Unknown error type - re-throw the error and Sentry will catch it
@ -242,8 +225,6 @@ class InvenTreeAPI {
if (response == null) { if (response == null) {
// Null (or error) response: Show dialog and exit // Null (or error) response: Show dialog and exit
await showServerError(context, errorMessage);
return false; return false;
} }
@ -322,6 +303,38 @@ class InvenTreeAPI {
}; };
} }
Future<bool> connectToServer(BuildContext context) async {
print("InvenTreeAPI().connectToServer()");
// Clear connection flag
_connected = false;
// Clear token
_token = '';
// Load selected profile
profile = await UserProfileDBManager().getSelectedProfile();
if (profile == null) {
await showErrorDialog(
context,
"Select Profile",
"User profile not selected"
);
return false;
}
_connecting = true;
_connect(context).then((result) {
print("_connect() returned result: ${result}");
_connecting = false;
return result;
});
}
// Perform a PATCH request // Perform a PATCH request
Future<http.Response> patch(String url, {Map<String, String> body}) async { Future<http.Response> patch(String url, {Map<String, String> body}) async {
var _url = makeApiUrl(url); var _url = makeApiUrl(url);
@ -405,7 +418,9 @@ class InvenTreeAPI {
Map<String, String> defaultHeaders() { Map<String, String> defaultHeaders() {
var headers = Map<String, String>(); var headers = Map<String, String>();
headers[HttpHeaders.authorizationHeader] = _authorizationHeader(_profile.username, _profile.password); if (profile != null) {
headers[HttpHeaders.authorizationHeader] = _authorizationHeader(profile.username, profile.password);
}
return headers; return headers;
} }

View File

@ -180,7 +180,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
_reload(); _reload();
// Attempt server login (this will load the newly selected profile // Attempt server login (this will load the newly selected profile
InvenTreeAPI().connect(context); InvenTreeAPI().connectToServer(context);
} }
void _deleteProfile(UserProfile profile) async { void _deleteProfile(UserProfile profile) async {
@ -220,7 +220,7 @@ class _InvenTreeLoginSettingsState extends State<InvenTreeLoginSettingsWidget> {
List<Widget> children = []; List<Widget> children = [];
if (profiles.length > 0) { if (profiles != null && profiles.length > 0) {
for (int idx = 0; idx < profiles.length; idx++) { for (int idx = 0; idx < profiles.length; idx++) {
UserProfile profile = profiles[idx]; UserProfile profile = profiles[idx];

View File

@ -44,109 +44,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
// Selected user profile // Selected user profile
UserProfile _profile; UserProfile _profile;
void _loadProfile() async { BuildContext _context;
final profile = await UserProfileDBManager().getSelectedProfile();
print("Loaded selected profile");
// If a different profile is selected, re-connect
if (_profile == null || (_profile.key != profile.key)) {
// TODO
}
_profile = profile;
setState(() {
});
}
ListTile _serverTile() {
// No profile selected
// Tap to select / create a profile
if (_profile == null) {
return ListTile(
title: Text("No Profile Selected"),
subtitle: Text("Tap to create or select a profile"),
leading: FaIcon(FontAwesomeIcons.user),
onTap: () {
_selectProfile();
},
);
}
// Profile is selected ...
if (InvenTreeAPI().isConnected()) {
return ListTile(
title: Text("Connected to ${_profile.server}"),
);
} else {
return ListTile(
title: Text("Could not connect to server"),
subtitle: Text("Error connecting to ${_profile.server}"),
leading: FaIcon(FontAwesomeIcons.times),
onTap: () {
_selectProfile();
},
);
}
}
void onConnectSuccess(String msg) async {
final profile = await UserProfileDBManager().getSelectedProfile();
String address = profile?.server ?? 'unknown server address';
_serverConnection = true;
_serverMessage = msg;
_serverStatus = "Connected to ${address}";
_serverStatusColor = Color.fromARGB(255, 50, 250, 50);
_serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor);
setState(() {});
}
void onConnectFailure(String msg) async {
final profile = await UserProfileDBManager().getSelectedProfile();
_serverConnection = false;
_serverMessage = msg;
_serverStatus = "Could not connect to ${profile?.server}";
_serverStatusColor = Color.fromARGB(255, 250, 50, 50);
_serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor);
setState(() {});
}
/*
* Test the server connection
*/
void _checkServerConnection(BuildContext context) async {
// Reset the connection status variables
_serverStatus = "Connecting to server";
_serverMessage = "";
_serverConnection = false;
_serverIcon = new FaIcon(FontAwesomeIcons.spinner);
_serverStatusColor = Color.fromARGB(255, 50, 50, 250);
InvenTreeAPI().connect(context).then((bool result) {
if (result) {
onConnectSuccess("");
} else {
onConnectFailure("Could not connect to server");
}
});
// Update widget state
setState(() {});
}
void _search() { void _search() {
if (!InvenTreeAPI().checkConnection(context)) return; if (!InvenTreeAPI().checkConnection(context)) return;
@ -210,8 +108,130 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
); );
} }
void _loadProfile() async {
final profile = await UserProfileDBManager().getSelectedProfile();
// If a different profile is selected, re-connect
if (_profile == null || (_profile.key != profile.key)) {
if (_context != null) {
print("Connecting Profile: ${profile.name} - ${profile.server}");
InvenTreeAPI().connectToServer(_context).then((result) {
setState(() {
});
});
setState(() {
});
}
}
_profile = profile;
setState(() {
});
}
ListTile _serverTile() {
// No profile selected
// Tap to select / create a profile
if (_profile == null) {
return ListTile(
title: Text("No Profile Selected"),
subtitle: Text("Tap to create or select a profile"),
leading: FaIcon(FontAwesomeIcons.server),
trailing: FaIcon(
FontAwesomeIcons.user,
color: Color.fromRGBO(250, 50, 50, 1),
),
onTap: () {
_selectProfile();
},
);
}
// Profile is selected ...
if (InvenTreeAPI().isConnecting()) {
return ListTile(
title: Text("Connecting to server..."),
subtitle: Text("${InvenTreeAPI().baseUrl}"),
leading: FaIcon(FontAwesomeIcons.server),
trailing: FaIcon(
FontAwesomeIcons.spinner,
color: Color.fromRGBO(50, 50, 250, 1),
)
);
} else if (InvenTreeAPI().isConnected()) {
return ListTile(
title: Text("Connected to server"),
subtitle: Text("${InvenTreeAPI().baseUrl}"),
leading: FaIcon(FontAwesomeIcons.server),
trailing: FaIcon(
FontAwesomeIcons.checkCircle,
color: Color.fromRGBO(50, 250, 50, 1)
),
onTap: () {
_selectProfile();
},
);
} else {
return ListTile(
title: Text("Could not connect to server"),
subtitle: Text("${_profile.server}"),
leading: FaIcon(FontAwesomeIcons.server),
trailing: FaIcon(
FontAwesomeIcons.timesCircle,
color: Color.fromRGBO(250, 50, 50, 1),
),
onTap: () {
_selectProfile();
},
);
}
}
void onConnectSuccess(String msg) async {
final profile = await UserProfileDBManager().getSelectedProfile();
String address = profile?.server ?? 'unknown server address';
_serverConnection = true;
_serverMessage = msg;
_serverStatus = "Connected to ${address}";
_serverStatusColor = Color.fromARGB(255, 50, 250, 50);
_serverIcon = new FaIcon(FontAwesomeIcons.checkCircle, color: _serverStatusColor);
setState(() {});
}
void onConnectFailure(String msg) async {
final profile = await UserProfileDBManager().getSelectedProfile();
_serverConnection = false;
_serverMessage = msg;
_serverStatus = "Could not connect to ${profile?.server}";
_serverStatusColor = Color.fromARGB(255, 250, 50, 50);
_serverIcon = new FaIcon(FontAwesomeIcons.timesCircle, color: _serverStatusColor);
setState(() {});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
_context = context;
_loadProfile();
// This method is rerun every time setState is called, for instance as done // This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above. // by the _incrementCounter method above.
// //
@ -369,6 +389,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> {
), ),
Spacer(), Spacer(),
*/ */
Spacer(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,