Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MQTT Support #258

Closed
wants to merge 12 commits into from
19 changes: 18 additions & 1 deletion lib/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ const kVSpacer40 = SizedBox(height: 40);
const kTabAnimationDuration = Duration(milliseconds: 200);
const kTabHeight = 32.0;
const kHeaderHeight = 32.0;
const kTopicHeaderHeight = 48.0;
const kSegmentHeight = 24.0;
const kTextButtonMinWidth = 44.0;

Expand Down Expand Up @@ -253,19 +254,30 @@ final kColorHttpMethodDelete = Colors.red.shade800;

enum RequestItemMenuOption { edit, delete, duplicate }

enum ProtocolType { http, mqttv3 }

enum RealtimeConnectionState {
connected,
connecting,
disconnected,
disconnecting
}

enum HTTPVerb { get, head, post, put, patch, delete }

enum FormDataType { text, file }

const kSupportedUriSchemes = ["https", "http"];
const kSupportedUriSchemes = ["https", "http", "mqtt", "mqtts", "ws", "wss"];
const kDefaultUriScheme = "https";

const kMethodsWithBody = [
HTTPVerb.post,
HTTPVerb.put,
HTTPVerb.patch,
HTTPVerb.delete,
];

const kDefaultProtocolType = ProtocolType.http;
const kDefaultHttpMethod = HTTPVerb.get;
const kDefaultContentType = ContentType.json;

Expand Down Expand Up @@ -529,10 +541,15 @@ const kCsvError =
"There seems to be an issue rendering this CSV. Please raise an issue in API Dash GitHub repo so that we can resolve it.";

const kHintTextUrlCard = "Enter API endpoint like https://$kDefaultUri/";
const kHintTextClientIdCard = "Enter Client ID";
const kLabelPlusNew = "+ New";
const kLabelSend = "Send";
const kLabelSending = "Sending..";
const kLabelBusy = "Busy";
const kLabelConnect = "Connect";
const kLabelDisconnect = "Disconnect";
const kLabelConnecting = "Connecting..";
const kLabelDisconnecting = "Disconnecting..";
const kLabelCopy = "Copy";
const kLabelSave = "Save";
const kLabelDownload = "Download";
Expand Down
2 changes: 2 additions & 0 deletions lib/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export 'request_model.dart';
export 'response_model.dart';
export 'settings_model.dart';
export 'form_data_model.dart';
export 'mqtt/mqtt_request_model.dart';
export 'mqtt/mqtt_response_model.dart';
238 changes: 238 additions & 0 deletions lib/models/mqtt/mqtt_request_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import 'package:flutter/foundation.dart';
import 'package:apidash/consts.dart';
import 'package:apidash/models/models.dart';

@immutable
class MQTTRequestModel {
const MQTTRequestModel({
this.username,
this.password,
this.keepAlive,
this.lwTopic,
this.lwMessage,
required this.lwQos,
required this.lwRetain,
required this.id,
required this.clientId,
this.url = "",
this.name = "",
this.description = "",
this.requestTabIndex = 0,
this.responseStatus,
this.message,
this.responseModel,
});

final String id;
final String clientId;
final String url;
final String name;
final String description;
final int requestTabIndex;
final int? responseStatus;
final String? message;
final String? username;
final String? password;
final int? keepAlive;
final String? lwTopic;
final String? lwMessage;
final int lwQos;
final bool lwRetain;

final MQTTResponseModel? responseModel;

MQTTRequestModel duplicate({
required String id,
}) {
return MQTTRequestModel(
id: id,
url: "",
name: "$name (copy)",
description: "",
requestTabIndex: 0,
responseStatus: null,
message: null,
username: null,
password: null,
keepAlive: null,
lwTopic: null,
lwMessage: null,
lwQos: 0,
lwRetain: false,
responseModel: null,
clientId: "",
);
}

MQTTRequestModel copyWith({
String? id,
HTTPVerb? method,
String? url,
String? name,
String? description,
int? requestTabIndex,
int? responseStatus,
String? message,
MQTTResponseModel? responseModel,
String? username,
String? password,
int? keepAlive,
String? lwTopic,
String? lwMessage,
int? lwQos,
bool? lwRetain,
String? clientId,
}) {
return MQTTRequestModel(
id: id ?? this.id,
url: url ?? this.url,
name: name ?? this.name,
description: description ?? this.description,
requestTabIndex: requestTabIndex ?? this.requestTabIndex,
responseStatus: responseStatus ?? this.responseStatus,
message: message ?? this.message,
responseModel: responseModel ?? this.responseModel,
username: username ?? this.username,
password: password ?? this.password,
keepAlive: keepAlive ?? this.keepAlive,
lwTopic: lwTopic ?? this.lwTopic,
lwMessage: lwMessage ?? this.lwMessage,
lwQos: lwQos ?? this.lwQos,
lwRetain: lwRetain ?? this.lwRetain,
clientId: clientId ?? this.clientId,
);
}

factory MQTTRequestModel.fromJson(Map<String, dynamic> data) {
MQTTResponseModel? responseModel;

final id = data["id"] as String;
final url = data["url"] as String;
final name = data["name"] as String?;
final description = data["description"] as String?;
final username = data["username"] as String?;
final password = data["password"] as String?;
final keepAlive = data["keepAlive"] as int?;
final lwTopic = data["lwTopic"] as String?;
final lwMessage = data["lwMessage"] as String?;
final lwQos = data["lwQos"] as int;
final lwRetain = data["lwRetain"] as bool;
final responseStatus = data["responseStatus"] as int?;
final message = data["message"] as String?;
final clientId = data["clientId"] as String;
final responseModelJson = data["responseModel"];

if (responseModelJson != null) {
responseModel = MQTTResponseModel.fromJson(
Map<String, dynamic>.from(responseModelJson));
} else {
responseModel = null;
}

return MQTTRequestModel(
id: id,
url: url,
clientId: clientId,
name: name ?? "",
description: description ?? "",
requestTabIndex: 0,
responseStatus: responseStatus,
message: message,
username: username ?? "",
password: password ?? "",
keepAlive: keepAlive,
lwTopic: lwTopic,
lwMessage: lwMessage,
lwQos: lwQos,
lwRetain: lwRetain,
responseModel: responseModel,
);
}

Map<String, dynamic> toJson({bool includeResponse = true}) {
return {
"id": id,
"url": url,
"name": name,
"description": description,
"clientId": clientId,
"username": username,
"password": password,
"keepAlive": keepAlive,
"lwTopic": lwTopic,
"lwMessage": lwMessage,
"lwQos": lwQos,
"lwRetain": lwRetain,
"responseStatus": includeResponse ? responseStatus : null,
"message": includeResponse ? message : null,
"responseModel": includeResponse ? responseModel?.toJson() : null,
};
}

@override
String toString() {
return [
"Request Id: $id",
"Request URL: $url",
"Request Name: $name",
"Request Description: $description",
"Client ID: $clientId",
"Username: $username",
"Password: $password",
"Keep Alive: ${keepAlive.toString()}",
"Last Will Topic: $lwTopic",
"Last Will Message: $lwMessage",
"Last Will QoS: ${lwQos.toString()}",
"Last Will Retain: $lwRetain",
"Request Tab Index: ${requestTabIndex.toString()}",
"Response Status: $responseStatus",
"Response Message: $message",
"Response: ${responseModel.toString()}"
].join("\n");
}

@override
bool operator ==(Object other) {
return other is MQTTRequestModel &&
other.runtimeType == runtimeType &&
other.id == id &&
other.url == url &&
clientId == other.clientId &&
other.name == name &&
other.description == description &&
other.username == username &&
other.password == password &&
other.keepAlive == keepAlive &&
other.lwTopic == lwTopic &&
other.lwMessage == lwMessage &&
other.lwQos == lwQos &&
other.lwRetain == lwRetain &&
other.requestTabIndex == requestTabIndex &&
other.responseStatus == responseStatus &&
other.message == message &&
other.responseModel == responseModel;
}

@override
int get hashCode {
return Object.hash(
runtimeType,
id,
url,
clientId,
name,
description,
username,
password,
keepAlive,
lwTopic,
lwMessage,
lwQos,
lwRetain,
requestTabIndex,
responseStatus,
message,
responseModel,
);
}
}
83 changes: 83 additions & 0 deletions lib/models/mqtt/mqtt_response_model.dart
mmjsmohit marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:flutter/foundation.dart';
import 'package:mqtt_client/mqtt_client.dart';

@immutable
class MQTTResponseModel {
const MQTTResponseModel({
this.topic,
this.mqttHeader,
this.payload,
this.lwRetain,
this.time,
});

final String? topic;
final MqttHeader? mqttHeader;
final String? payload;
final bool? lwRetain;
final Duration? time;

factory MQTTResponseModel.fromJson(Map<String, dynamic> data) {
Duration? timeElapsed;
final topic = data["topic"] as String?;
final mqttHeader = data["mqttHeader"] as MqttHeader?;
final payload = data["payload"] as String?;
final lwRetain = data["lwRetain"] as bool?;
final time = data["time"] as int?;

if (time != null) {
timeElapsed = Duration(microseconds: time);
}
return MQTTResponseModel(
topic: topic,
mqttHeader: mqttHeader,
payload: payload,
lwRetain: lwRetain,
time: timeElapsed,
);
}

Map<String, dynamic> toJson() {
return {
"topic": topic,
"mqttHeader": mqttHeader,
"payload": payload,
"lwRetain": lwRetain,
"time": time?.inMicroseconds,
};
}

@override
String toString() {
return [
"Topic: $topic",
"MQTT Header: $mqttHeader",
"Payload: $payload",
"Last Will Retain: $lwRetain",
"Response Time: $time",
].join("\n");
}

@override
bool operator ==(Object other) {
return other is MQTTResponseModel &&
other.runtimeType == runtimeType &&
other.topic == topic &&
other.mqttHeader == mqttHeader &&
other.payload == payload &&
other.lwRetain == lwRetain &&
other.time == time;
}

@override
int get hashCode {
return Object.hash(
runtimeType,
topic,
mqttHeader,
payload,
lwRetain,
time,
);
}
}
Loading