Skip to content

Instantly share code, notes, and snippets.

@LenniCodes
Created September 21, 2021 21:19
Show Gist options
  • Save LenniCodes/b5b44bfc92157e62536bc9d418aeca76 to your computer and use it in GitHub Desktop.
Save LenniCodes/b5b44bfc92157e62536bc9d418aeca76 to your computer and use it in GitHub Desktop.
Http Core
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:spectrumhome/utils/system.dart';
import 'package:spectrumhome/utils/notification_manager.dart' as manager;
const String defaultIP = "localhost:8181";
String _ip = defaultIP;
const int requestDelay = 10;
const int threadTime = 3;
ConnectionState apiState = ConnectionState.PENDING;
enum ConnectionState { CONNECTED, PENDING, DISCONNECTED }
class APIConnectionEvent extends Event {
final ConnectionState state;
APIConnectionEvent(this.state);
}
void _setConnectionState(ConnectionState state) {
if (apiState == state) return;
apiState = state;
call(APIConnectionEvent(state));
}
class ApiIPChangedEvent extends Event {
final String ip;
ApiIPChangedEvent(this.ip);
}
Map services = {
"connectionInfo": "api/connection/info",
"connectionScan": "api/connection/scan",
"user": "api/user",
"device": "api/device",
"type": "api/type"
};
void changeIP(String ipChanged) {
_ip = ipChanged;
stopAPITasks();
_setConnectionState(ConnectionState.PENDING);
call(ApiIPChangedEvent(ipChanged));
}
void setIPRaw(String ipChanged) {
_ip = ipChanged;
}
String ip() {
return _ip;
}
int taskTime = 0;
int taskIterations = 0;
String? currentTask;
bool cancelTask = false;
Map<String, bool> taskWorker = {};
List<APITaskController> controllers = [];
void _clearTask() {
if (currentTask == null) return;
taskIterations = 0;
taskTime = 0;
taskWorker.remove(currentTask);
List<APITaskController> toDelete = [];
controllers.forEach((element) {
if (element.key == currentTask) toDelete.add(element);
});
controllers.removeWhere((element) => toDelete.contains(element));
currentTask = null;
}
void stopAPIOfGroup({required String group}) {
print("Stopping API-Group \"$group\"...");
controllers.forEach((element) {
if (element.group != null && element.group == group) element.stop();
});
}
void stopAPITasks() {
taskWorker.forEach((key, value) => taskWorker[key] = false);
}
void stopCurrentAPITask() {
cancelTask = true;
}
void stopAPITask({String? key, String? service, String? method}) {
String? keyword = key != null
? key
: (service != null && method != null
? buildAPITaskID(services[service], method)
: null);
if (keyword == null) return;
if (taskWorker.containsKey(keyword)) taskWorker[keyword] = false;
}
List<String> doneTasks = [];
Future<Response> request(String service, String method, Map body,
{String? token,
int? timeout,
String? keyword,
APITaskController? controller}) async {
String beginIP = _ip;
String apiPath = services[service];
String key = keyword != null ? keyword : buildAPITaskID(apiPath, method);
if (doneTasks.contains(key)) {
doneTasks.remove(key);
}
if (controller != null) {
controller.key = key;
controllers.add(controller);
}
taskWorker[key] = true;
print("Facing \"$key\" now...");
if (currentTask != null && currentTask != key) {
while (currentTask != null) {
if (!taskWorker.containsKey(key) || !taskWorker[key]!) {
print(" - Removing \"$key\" from Queue...");
if (controller != null) controllers.remove(controller);
return Response(code: 408, message: "Cancelled");
}
await Future.delayed(Duration(seconds: threadTime));
}
}
if (apiState == ConnectionState.DISCONNECTED)
_setConnectionState(ConnectionState.PENDING);
currentTask = key;
taskTime = DateTime.now().millisecondsSinceEpoch;
taskIterations += 1;
try {
var response = await http.post(Uri.parse("http://" + _ip + "/" + apiPath),
body: jsonEncode({"method": method, "params": body}),
headers: {
"SPECTRUM-AUTH": token != null ? token : sessionToken ?? ""
}).timeout(Duration(seconds: 10));
var result = jsonDecode(response.body);
if (beginIP != _ip) throw Exception();
_clearTask();
_setConnectionState(ConnectionState.CONNECTED);
if (response.statusCode != 200 && result.containsKey("error")) {
manager.addToQueue(text: result["error"]);
return Response(code: response.statusCode, message: result["error"]);
} else {
if (!doneTasks.contains(key)) {
doneTasks.add(key);
return Response(obj: result, code: 200);
} else
return Response(code: 408, message: "Internal error.");
}
} catch (exception) {
_setConnectionState(ConnectionState.DISCONNECTED);
manager.addToQueue(text: "Keine Internetverbindung.");
print("Error connecting to API: " + exception.toString());
if (beginIP != _ip) cancelTask = true;
if (timeout != null && taskIterations >= timeout) cancelTask = true;
if (!taskWorker.containsKey(key) || !taskWorker[key]!) cancelTask = true;
if (cancelTask) {
print(" - Cancelling current running Task \"$currentTask\"...");
_clearTask();
manager.addToQueue(text: "Versuche es später noch einmal.");
cancelTask = false;
return Response(code: 408, message: "Timed Out");
}
while (DateTime.now().millisecondsSinceEpoch - taskTime <
(requestDelay * 1000)) {
await Future.delayed(Duration(seconds: threadTime));
}
if (currentTask != null && !doneTasks.contains(key)) {
print("trying \"$currentTask\" again...");
return await request(service, method, body);
}
return Response(code: 408, message: "Internal error.");
}
}
class APITaskController {
String? key;
String? group;
APITaskController({this.group});
void stop() {
stopAPITask(key: key);
}
}
String buildAPITaskID(String apiPath, String method) {
return apiPath + method;
}
class Response {
String message;
int code;
dynamic obj;
bool success = false;
bool invalidRequest = false;
Response(
{this.message = "Success.",
this.obj,
this.code = 400,
this.invalidRequest = false}) {
success = obj != null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment