diff --git a/lib/consts.dart b/lib/consts.dart index 81f9c8f21a..a53a0afeba 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -430,6 +430,9 @@ const kRaiseIssue = "\nPlease raise an issue in API Dash GitHub repo so that we can resolve it."; const kHintTextUrlCard = "Enter API endpoint like https://$kDefaultUri/"; +const kHintTextWsCard = "Enter WebSocket endpoint like wss://echo.websocket.org"; +const kHintTextMqttCard = "Enter MQTT broker URL like mqtt://broker.emqx.io"; +const kHintTextGrpcCard = "Enter gRPC host like localhost:50051"; const kLabelPlusNew = "+ New"; const kLabelMoreOptions = "More Options"; const kLabelSend = "Send"; diff --git a/lib/models/history_meta_model.dart b/lib/models/history_meta_model.dart index c0226086b5..578210a84f 100644 --- a/lib/models/history_meta_model.dart +++ b/lib/models/history_meta_model.dart @@ -5,7 +5,7 @@ part 'history_meta_model.freezed.dart'; part 'history_meta_model.g.dart'; @freezed -class HistoryMetaModel with _$HistoryMetaModel { +abstract class HistoryMetaModel with _$HistoryMetaModel { const factory HistoryMetaModel({ required String historyId, required String requestId, diff --git a/lib/models/history_meta_model.freezed.dart b/lib/models/history_meta_model.freezed.dart index 97a068b223..21ac074f80 100644 --- a/lib/models/history_meta_model.freezed.dart +++ b/lib/models/history_meta_model.freezed.dart @@ -1,5 +1,5 @@ -// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark @@ -9,307 +9,290 @@ part of 'history_meta_model.dart'; // FreezedGenerator // ************************************************************************** +// dart format off T _$identity(T value) => value; -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -HistoryMetaModel _$HistoryMetaModelFromJson(Map json) { - return _HistoryMetaModel.fromJson(json); -} - /// @nodoc mixin _$HistoryMetaModel { - String get historyId => throw _privateConstructorUsedError; - String get requestId => throw _privateConstructorUsedError; - APIType get apiType => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - String get url => throw _privateConstructorUsedError; - HTTPVerb get method => throw _privateConstructorUsedError; - int get responseStatus => throw _privateConstructorUsedError; - DateTime get timeStamp => throw _privateConstructorUsedError; + + String get historyId; String get requestId; APIType get apiType; String get name; String get url; HTTPVerb get method; int get responseStatus; DateTime get timeStamp; +/// Create a copy of HistoryMetaModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$HistoryMetaModelCopyWith get copyWith => _$HistoryMetaModelCopyWithImpl(this as HistoryMetaModel, _$identity); /// Serializes this HistoryMetaModel to a JSON map. - Map toJson() => throw _privateConstructorUsedError; + Map toJson(); + - /// Create a copy of HistoryMetaModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $HistoryMetaModelCopyWith get copyWith => - throw _privateConstructorUsedError; +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is HistoryMetaModel&&(identical(other.historyId, historyId) || other.historyId == historyId)&&(identical(other.requestId, requestId) || other.requestId == requestId)&&(identical(other.apiType, apiType) || other.apiType == apiType)&&(identical(other.name, name) || other.name == name)&&(identical(other.url, url) || other.url == url)&&(identical(other.method, method) || other.method == method)&&(identical(other.responseStatus, responseStatus) || other.responseStatus == responseStatus)&&(identical(other.timeStamp, timeStamp) || other.timeStamp == timeStamp)); } -/// @nodoc -abstract class $HistoryMetaModelCopyWith<$Res> { - factory $HistoryMetaModelCopyWith( - HistoryMetaModel value, $Res Function(HistoryMetaModel) then) = - _$HistoryMetaModelCopyWithImpl<$Res, HistoryMetaModel>; - @useResult - $Res call( - {String historyId, - String requestId, - APIType apiType, - String name, - String url, - HTTPVerb method, - int responseStatus, - DateTime timeStamp}); +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,historyId,requestId,apiType,name,url,method,responseStatus,timeStamp); + +@override +String toString() { + return 'HistoryMetaModel(historyId: $historyId, requestId: $requestId, apiType: $apiType, name: $name, url: $url, method: $method, responseStatus: $responseStatus, timeStamp: $timeStamp)'; } -/// @nodoc -class _$HistoryMetaModelCopyWithImpl<$Res, $Val extends HistoryMetaModel> - implements $HistoryMetaModelCopyWith<$Res> { - _$HistoryMetaModelCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of HistoryMetaModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? historyId = null, - Object? requestId = null, - Object? apiType = null, - Object? name = null, - Object? url = null, - Object? method = null, - Object? responseStatus = null, - Object? timeStamp = null, - }) { - return _then(_value.copyWith( - historyId: null == historyId - ? _value.historyId - : historyId // ignore: cast_nullable_to_non_nullable - as String, - requestId: null == requestId - ? _value.requestId - : requestId // ignore: cast_nullable_to_non_nullable - as String, - apiType: null == apiType - ? _value.apiType - : apiType // ignore: cast_nullable_to_non_nullable - as APIType, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - method: null == method - ? _value.method - : method // ignore: cast_nullable_to_non_nullable - as HTTPVerb, - responseStatus: null == responseStatus - ? _value.responseStatus - : responseStatus // ignore: cast_nullable_to_non_nullable - as int, - timeStamp: null == timeStamp - ? _value.timeStamp - : timeStamp // ignore: cast_nullable_to_non_nullable - as DateTime, - ) as $Val); - } + } /// @nodoc -abstract class _$$HistoryMetaModelImplCopyWith<$Res> +abstract mixin class $HistoryMetaModelCopyWith<$Res> { + factory $HistoryMetaModelCopyWith(HistoryMetaModel value, $Res Function(HistoryMetaModel) _then) = _$HistoryMetaModelCopyWithImpl; +@useResult +$Res call({ + String historyId, String requestId, APIType apiType, String name, String url, HTTPVerb method, int responseStatus, DateTime timeStamp +}); + + + + +} +/// @nodoc +class _$HistoryMetaModelCopyWithImpl<$Res> implements $HistoryMetaModelCopyWith<$Res> { - factory _$$HistoryMetaModelImplCopyWith(_$HistoryMetaModelImpl value, - $Res Function(_$HistoryMetaModelImpl) then) = - __$$HistoryMetaModelImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String historyId, - String requestId, - APIType apiType, - String name, - String url, - HTTPVerb method, - int responseStatus, - DateTime timeStamp}); + _$HistoryMetaModelCopyWithImpl(this._self, this._then); + + final HistoryMetaModel _self; + final $Res Function(HistoryMetaModel) _then; + +/// Create a copy of HistoryMetaModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? historyId = null,Object? requestId = null,Object? apiType = null,Object? name = null,Object? url = null,Object? method = null,Object? responseStatus = null,Object? timeStamp = null,}) { + return _then(_self.copyWith( +historyId: null == historyId ? _self.historyId : historyId // ignore: cast_nullable_to_non_nullable +as String,requestId: null == requestId ? _self.requestId : requestId // ignore: cast_nullable_to_non_nullable +as String,apiType: null == apiType ? _self.apiType : apiType // ignore: cast_nullable_to_non_nullable +as APIType,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable +as String,method: null == method ? _self.method : method // ignore: cast_nullable_to_non_nullable +as HTTPVerb,responseStatus: null == responseStatus ? _self.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable +as int,timeStamp: null == timeStamp ? _self.timeStamp : timeStamp // ignore: cast_nullable_to_non_nullable +as DateTime, + )); +} + +} + + +/// Adds pattern-matching-related methods to [HistoryMetaModel]. +extension HistoryMetaModelPatterns on HistoryMetaModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _HistoryMetaModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _HistoryMetaModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _HistoryMetaModel value) $default,){ +final _that = this; +switch (_that) { +case _HistoryMetaModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _HistoryMetaModel value)? $default,){ +final _that = this; +switch (_that) { +case _HistoryMetaModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String historyId, String requestId, APIType apiType, String name, String url, HTTPVerb method, int responseStatus, DateTime timeStamp)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _HistoryMetaModel() when $default != null: +return $default(_that.historyId,_that.requestId,_that.apiType,_that.name,_that.url,_that.method,_that.responseStatus,_that.timeStamp);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String historyId, String requestId, APIType apiType, String name, String url, HTTPVerb method, int responseStatus, DateTime timeStamp) $default,) {final _that = this; +switch (_that) { +case _HistoryMetaModel(): +return $default(_that.historyId,_that.requestId,_that.apiType,_that.name,_that.url,_that.method,_that.responseStatus,_that.timeStamp);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String historyId, String requestId, APIType apiType, String name, String url, HTTPVerb method, int responseStatus, DateTime timeStamp)? $default,) {final _that = this; +switch (_that) { +case _HistoryMetaModel() when $default != null: +return $default(_that.historyId,_that.requestId,_that.apiType,_that.name,_that.url,_that.method,_that.responseStatus,_that.timeStamp);case _: + return null; + +} } -/// @nodoc -class __$$HistoryMetaModelImplCopyWithImpl<$Res> - extends _$HistoryMetaModelCopyWithImpl<$Res, _$HistoryMetaModelImpl> - implements _$$HistoryMetaModelImplCopyWith<$Res> { - __$$HistoryMetaModelImplCopyWithImpl(_$HistoryMetaModelImpl _value, - $Res Function(_$HistoryMetaModelImpl) _then) - : super(_value, _then); - - /// Create a copy of HistoryMetaModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? historyId = null, - Object? requestId = null, - Object? apiType = null, - Object? name = null, - Object? url = null, - Object? method = null, - Object? responseStatus = null, - Object? timeStamp = null, - }) { - return _then(_$HistoryMetaModelImpl( - historyId: null == historyId - ? _value.historyId - : historyId // ignore: cast_nullable_to_non_nullable - as String, - requestId: null == requestId - ? _value.requestId - : requestId // ignore: cast_nullable_to_non_nullable - as String, - apiType: null == apiType - ? _value.apiType - : apiType // ignore: cast_nullable_to_non_nullable - as APIType, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - method: null == method - ? _value.method - : method // ignore: cast_nullable_to_non_nullable - as HTTPVerb, - responseStatus: null == responseStatus - ? _value.responseStatus - : responseStatus // ignore: cast_nullable_to_non_nullable - as int, - timeStamp: null == timeStamp - ? _value.timeStamp - : timeStamp // ignore: cast_nullable_to_non_nullable - as DateTime, - )); - } } /// @nodoc @JsonSerializable() -class _$HistoryMetaModelImpl implements _HistoryMetaModel { - const _$HistoryMetaModelImpl( - {required this.historyId, - required this.requestId, - required this.apiType, - this.name = "", - required this.url, - required this.method, - required this.responseStatus, - required this.timeStamp}); - - factory _$HistoryMetaModelImpl.fromJson(Map json) => - _$$HistoryMetaModelImplFromJson(json); - - @override - final String historyId; - @override - final String requestId; - @override - final APIType apiType; - @override - @JsonKey() - final String name; - @override - final String url; - @override - final HTTPVerb method; - @override - final int responseStatus; - @override - final DateTime timeStamp; - - @override - String toString() { - return 'HistoryMetaModel(historyId: $historyId, requestId: $requestId, apiType: $apiType, name: $name, url: $url, method: $method, responseStatus: $responseStatus, timeStamp: $timeStamp)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$HistoryMetaModelImpl && - (identical(other.historyId, historyId) || - other.historyId == historyId) && - (identical(other.requestId, requestId) || - other.requestId == requestId) && - (identical(other.apiType, apiType) || other.apiType == apiType) && - (identical(other.name, name) || other.name == name) && - (identical(other.url, url) || other.url == url) && - (identical(other.method, method) || other.method == method) && - (identical(other.responseStatus, responseStatus) || - other.responseStatus == responseStatus) && - (identical(other.timeStamp, timeStamp) || - other.timeStamp == timeStamp)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, historyId, requestId, apiType, - name, url, method, responseStatus, timeStamp); - - /// Create a copy of HistoryMetaModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$HistoryMetaModelImplCopyWith<_$HistoryMetaModelImpl> get copyWith => - __$$HistoryMetaModelImplCopyWithImpl<_$HistoryMetaModelImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$HistoryMetaModelImplToJson( - this, - ); - } + +class _HistoryMetaModel implements HistoryMetaModel { + const _HistoryMetaModel({required this.historyId, required this.requestId, required this.apiType, this.name = "", required this.url, required this.method, required this.responseStatus, required this.timeStamp}); + factory _HistoryMetaModel.fromJson(Map json) => _$HistoryMetaModelFromJson(json); + +@override final String historyId; +@override final String requestId; +@override final APIType apiType; +@override@JsonKey() final String name; +@override final String url; +@override final HTTPVerb method; +@override final int responseStatus; +@override final DateTime timeStamp; + +/// Create a copy of HistoryMetaModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$HistoryMetaModelCopyWith<_HistoryMetaModel> get copyWith => __$HistoryMetaModelCopyWithImpl<_HistoryMetaModel>(this, _$identity); + +@override +Map toJson() { + return _$HistoryMetaModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _HistoryMetaModel&&(identical(other.historyId, historyId) || other.historyId == historyId)&&(identical(other.requestId, requestId) || other.requestId == requestId)&&(identical(other.apiType, apiType) || other.apiType == apiType)&&(identical(other.name, name) || other.name == name)&&(identical(other.url, url) || other.url == url)&&(identical(other.method, method) || other.method == method)&&(identical(other.responseStatus, responseStatus) || other.responseStatus == responseStatus)&&(identical(other.timeStamp, timeStamp) || other.timeStamp == timeStamp)); } -abstract class _HistoryMetaModel implements HistoryMetaModel { - const factory _HistoryMetaModel( - {required final String historyId, - required final String requestId, - required final APIType apiType, - final String name, - required final String url, - required final HTTPVerb method, - required final int responseStatus, - required final DateTime timeStamp}) = _$HistoryMetaModelImpl; - - factory _HistoryMetaModel.fromJson(Map json) = - _$HistoryMetaModelImpl.fromJson; - - @override - String get historyId; - @override - String get requestId; - @override - APIType get apiType; - @override - String get name; - @override - String get url; - @override - HTTPVerb get method; - @override - int get responseStatus; - @override - DateTime get timeStamp; - - /// Create a copy of HistoryMetaModel - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$HistoryMetaModelImplCopyWith<_$HistoryMetaModelImpl> get copyWith => - throw _privateConstructorUsedError; +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,historyId,requestId,apiType,name,url,method,responseStatus,timeStamp); + +@override +String toString() { + return 'HistoryMetaModel(historyId: $historyId, requestId: $requestId, apiType: $apiType, name: $name, url: $url, method: $method, responseStatus: $responseStatus, timeStamp: $timeStamp)'; } + + +} + +/// @nodoc +abstract mixin class _$HistoryMetaModelCopyWith<$Res> implements $HistoryMetaModelCopyWith<$Res> { + factory _$HistoryMetaModelCopyWith(_HistoryMetaModel value, $Res Function(_HistoryMetaModel) _then) = __$HistoryMetaModelCopyWithImpl; +@override @useResult +$Res call({ + String historyId, String requestId, APIType apiType, String name, String url, HTTPVerb method, int responseStatus, DateTime timeStamp +}); + + + + +} +/// @nodoc +class __$HistoryMetaModelCopyWithImpl<$Res> + implements _$HistoryMetaModelCopyWith<$Res> { + __$HistoryMetaModelCopyWithImpl(this._self, this._then); + + final _HistoryMetaModel _self; + final $Res Function(_HistoryMetaModel) _then; + +/// Create a copy of HistoryMetaModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? historyId = null,Object? requestId = null,Object? apiType = null,Object? name = null,Object? url = null,Object? method = null,Object? responseStatus = null,Object? timeStamp = null,}) { + return _then(_HistoryMetaModel( +historyId: null == historyId ? _self.historyId : historyId // ignore: cast_nullable_to_non_nullable +as String,requestId: null == requestId ? _self.requestId : requestId // ignore: cast_nullable_to_non_nullable +as String,apiType: null == apiType ? _self.apiType : apiType // ignore: cast_nullable_to_non_nullable +as APIType,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable +as String,method: null == method ? _self.method : method // ignore: cast_nullable_to_non_nullable +as HTTPVerb,responseStatus: null == responseStatus ? _self.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable +as int,timeStamp: null == timeStamp ? _self.timeStamp : timeStamp // ignore: cast_nullable_to_non_nullable +as DateTime, + )); +} + + +} + +// dart format on diff --git a/lib/models/history_meta_model.g.dart b/lib/models/history_meta_model.g.dart index ede68a2965..6888ce81cb 100644 --- a/lib/models/history_meta_model.g.dart +++ b/lib/models/history_meta_model.g.dart @@ -6,9 +6,8 @@ part of 'history_meta_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$HistoryMetaModelImpl _$$HistoryMetaModelImplFromJson( - Map json) => - _$HistoryMetaModelImpl( +_HistoryMetaModel _$HistoryMetaModelFromJson(Map json) => + _HistoryMetaModel( historyId: json['historyId'] as String, requestId: json['requestId'] as String, apiType: $enumDecode(_$APITypeEnumMap, json['apiType']), @@ -19,8 +18,7 @@ _$HistoryMetaModelImpl _$$HistoryMetaModelImplFromJson( timeStamp: DateTime.parse(json['timeStamp'] as String), ); -Map _$$HistoryMetaModelImplToJson( - _$HistoryMetaModelImpl instance) => +Map _$HistoryMetaModelToJson(_HistoryMetaModel instance) => { 'historyId': instance.historyId, 'requestId': instance.requestId, @@ -36,6 +34,9 @@ const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.ai: 'ai', APIType.graphql: 'graphql', + APIType.websocket: 'websocket', + APIType.mqtt: 'mqtt', + APIType.grpc: 'grpc', }; const _$HTTPVerbEnumMap = { diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index 1169dc7e23..1a49e293b4 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -6,7 +6,7 @@ part 'history_request_model.freezed.dart'; part 'history_request_model.g.dart'; @freezed -class HistoryRequestModel with _$HistoryRequestModel { +abstract class HistoryRequestModel with _$HistoryRequestModel { @JsonSerializable( explicitToJson: true, anyMap: true, diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index dd553171ed..3e849e3256 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -1,5 +1,5 @@ -// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark @@ -9,398 +9,398 @@ part of 'history_request_model.dart'; // FreezedGenerator // ************************************************************************** +// dart format off T _$identity(T value) => value; -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -HistoryRequestModel _$HistoryRequestModelFromJson(Map json) { - return _HistoryRequestModel.fromJson(json); -} - /// @nodoc mixin _$HistoryRequestModel { - String get historyId => throw _privateConstructorUsedError; - HistoryMetaModel get metaData => throw _privateConstructorUsedError; - HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; - AIRequestModel? get aiRequestModel => throw _privateConstructorUsedError; - HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; - String? get preRequestScript => throw _privateConstructorUsedError; - String? get postRequestScript => throw _privateConstructorUsedError; - AuthModel? get authModel => throw _privateConstructorUsedError; + + String get historyId; HistoryMetaModel get metaData; HttpRequestModel? get httpRequestModel; AIRequestModel? get aiRequestModel; HttpResponseModel get httpResponseModel; String? get preRequestScript; String? get postRequestScript; AuthModel? get authModel; +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$HistoryRequestModelCopyWith get copyWith => _$HistoryRequestModelCopyWithImpl(this as HistoryRequestModel, _$identity); /// Serializes this HistoryRequestModel to a JSON map. - Map toJson() => throw _privateConstructorUsedError; + Map toJson(); - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $HistoryRequestModelCopyWith get copyWith => - throw _privateConstructorUsedError; + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is HistoryRequestModel&&(identical(other.historyId, historyId) || other.historyId == historyId)&&(identical(other.metaData, metaData) || other.metaData == metaData)&&(identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel)&&(identical(other.aiRequestModel, aiRequestModel) || other.aiRequestModel == aiRequestModel)&&(identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel)&&(identical(other.preRequestScript, preRequestScript) || other.preRequestScript == preRequestScript)&&(identical(other.postRequestScript, postRequestScript) || other.postRequestScript == postRequestScript)&&(identical(other.authModel, authModel) || other.authModel == authModel)); } -/// @nodoc -abstract class $HistoryRequestModelCopyWith<$Res> { - factory $HistoryRequestModelCopyWith( - HistoryRequestModel value, $Res Function(HistoryRequestModel) then) = - _$HistoryRequestModelCopyWithImpl<$Res, HistoryRequestModel>; - @useResult - $Res call( - {String historyId, - HistoryMetaModel metaData, - HttpRequestModel? httpRequestModel, - AIRequestModel? aiRequestModel, - HttpResponseModel httpResponseModel, - String? preRequestScript, - String? postRequestScript, - AuthModel? authModel}); - - $HistoryMetaModelCopyWith<$Res> get metaData; - $HttpRequestModelCopyWith<$Res>? get httpRequestModel; - $AIRequestModelCopyWith<$Res>? get aiRequestModel; - $HttpResponseModelCopyWith<$Res> get httpResponseModel; - $AuthModelCopyWith<$Res>? get authModel; +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,historyId,metaData,httpRequestModel,aiRequestModel,httpResponseModel,preRequestScript,postRequestScript,authModel); + +@override +String toString() { + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, aiRequestModel: $aiRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; +} + + } /// @nodoc -class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> +abstract mixin class $HistoryRequestModelCopyWith<$Res> { + factory $HistoryRequestModelCopyWith(HistoryRequestModel value, $Res Function(HistoryRequestModel) _then) = _$HistoryRequestModelCopyWithImpl; +@useResult +$Res call({ + String historyId, HistoryMetaModel metaData, HttpRequestModel? httpRequestModel, AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel +}); + + +$HistoryMetaModelCopyWith<$Res> get metaData;$HttpRequestModelCopyWith<$Res>? get httpRequestModel;$AIRequestModelCopyWith<$Res>? get aiRequestModel;$HttpResponseModelCopyWith<$Res> get httpResponseModel;$AuthModelCopyWith<$Res>? get authModel; + +} +/// @nodoc +class _$HistoryRequestModelCopyWithImpl<$Res> implements $HistoryRequestModelCopyWith<$Res> { - _$HistoryRequestModelCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? historyId = null, - Object? metaData = null, - Object? httpRequestModel = freezed, - Object? aiRequestModel = freezed, - Object? httpResponseModel = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, - Object? authModel = freezed, - }) { - return _then(_value.copyWith( - historyId: null == historyId - ? _value.historyId - : historyId // ignore: cast_nullable_to_non_nullable - as String, - metaData: null == metaData - ? _value.metaData - : metaData // ignore: cast_nullable_to_non_nullable - as HistoryMetaModel, - httpRequestModel: freezed == httpRequestModel - ? _value.httpRequestModel - : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel?, - aiRequestModel: freezed == aiRequestModel - ? _value.aiRequestModel - : aiRequestModel // ignore: cast_nullable_to_non_nullable - as AIRequestModel?, - httpResponseModel: null == httpResponseModel - ? _value.httpResponseModel - : httpResponseModel // ignore: cast_nullable_to_non_nullable - as HttpResponseModel, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, - ) as $Val); + _$HistoryRequestModelCopyWithImpl(this._self, this._then); + + final HistoryRequestModel _self; + final $Res Function(HistoryRequestModel) _then; + +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? historyId = null,Object? metaData = null,Object? httpRequestModel = freezed,Object? aiRequestModel = freezed,Object? httpResponseModel = null,Object? preRequestScript = freezed,Object? postRequestScript = freezed,Object? authModel = freezed,}) { + return _then(_self.copyWith( +historyId: null == historyId ? _self.historyId : historyId // ignore: cast_nullable_to_non_nullable +as String,metaData: null == metaData ? _self.metaData : metaData // ignore: cast_nullable_to_non_nullable +as HistoryMetaModel,httpRequestModel: freezed == httpRequestModel ? _self.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable +as HttpRequestModel?,aiRequestModel: freezed == aiRequestModel ? _self.aiRequestModel : aiRequestModel // ignore: cast_nullable_to_non_nullable +as AIRequestModel?,httpResponseModel: null == httpResponseModel ? _self.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable +as HttpResponseModel,preRequestScript: freezed == preRequestScript ? _self.preRequestScript : preRequestScript // ignore: cast_nullable_to_non_nullable +as String?,postRequestScript: freezed == postRequestScript ? _self.postRequestScript : postRequestScript // ignore: cast_nullable_to_non_nullable +as String?,authModel: freezed == authModel ? _self.authModel : authModel // ignore: cast_nullable_to_non_nullable +as AuthModel?, + )); +} +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HistoryMetaModelCopyWith<$Res> get metaData { + + return $HistoryMetaModelCopyWith<$Res>(_self.metaData, (value) { + return _then(_self.copyWith(metaData: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpRequestModelCopyWith<$Res>? get httpRequestModel { + if (_self.httpRequestModel == null) { + return null; } - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $HistoryMetaModelCopyWith<$Res> get metaData { - return $HistoryMetaModelCopyWith<$Res>(_value.metaData, (value) { - return _then(_value.copyWith(metaData: value) as $Val); - }); + return $HttpRequestModelCopyWith<$Res>(_self.httpRequestModel!, (value) { + return _then(_self.copyWith(httpRequestModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AIRequestModelCopyWith<$Res>? get aiRequestModel { + if (_self.aiRequestModel == null) { + return null; } - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $HttpRequestModelCopyWith<$Res>? get httpRequestModel { - if (_value.httpRequestModel == null) { - return null; - } - - return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel!, (value) { - return _then(_value.copyWith(httpRequestModel: value) as $Val); - }); + return $AIRequestModelCopyWith<$Res>(_self.aiRequestModel!, (value) { + return _then(_self.copyWith(aiRequestModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpResponseModelCopyWith<$Res> get httpResponseModel { + + return $HttpResponseModelCopyWith<$Res>(_self.httpResponseModel, (value) { + return _then(_self.copyWith(httpResponseModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AuthModelCopyWith<$Res>? get authModel { + if (_self.authModel == null) { + return null; } - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AIRequestModelCopyWith<$Res>? get aiRequestModel { - if (_value.aiRequestModel == null) { - return null; - } - - return $AIRequestModelCopyWith<$Res>(_value.aiRequestModel!, (value) { - return _then(_value.copyWith(aiRequestModel: value) as $Val); - }); - } + return $AuthModelCopyWith<$Res>(_self.authModel!, (value) { + return _then(_self.copyWith(authModel: value)); + }); +} +} - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $HttpResponseModelCopyWith<$Res> get httpResponseModel { - return $HttpResponseModelCopyWith<$Res>(_value.httpResponseModel, (value) { - return _then(_value.copyWith(httpResponseModel: value) as $Val); - }); - } - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AuthModelCopyWith<$Res>? get authModel { - if (_value.authModel == null) { - return null; - } - - return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { - return _then(_value.copyWith(authModel: value) as $Val); - }); - } +/// Adds pattern-matching-related methods to [HistoryRequestModel]. +extension HistoryRequestModelPatterns on HistoryRequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _HistoryRequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _HistoryRequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + } +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _HistoryRequestModel value) $default,){ +final _that = this; +switch (_that) { +case _HistoryRequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); -/// @nodoc -abstract class _$$HistoryRequestModelImplCopyWith<$Res> - implements $HistoryRequestModelCopyWith<$Res> { - factory _$$HistoryRequestModelImplCopyWith(_$HistoryRequestModelImpl value, - $Res Function(_$HistoryRequestModelImpl) then) = - __$$HistoryRequestModelImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String historyId, - HistoryMetaModel metaData, - HttpRequestModel? httpRequestModel, - AIRequestModel? aiRequestModel, - HttpResponseModel httpResponseModel, - String? preRequestScript, - String? postRequestScript, - AuthModel? authModel}); - - @override - $HistoryMetaModelCopyWith<$Res> get metaData; - @override - $HttpRequestModelCopyWith<$Res>? get httpRequestModel; - @override - $AIRequestModelCopyWith<$Res>? get aiRequestModel; - @override - $HttpResponseModelCopyWith<$Res> get httpResponseModel; - @override - $AuthModelCopyWith<$Res>? get authModel; +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _HistoryRequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _HistoryRequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String historyId, HistoryMetaModel metaData, HttpRequestModel? httpRequestModel, AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _HistoryRequestModel() when $default != null: +return $default(_that.historyId,_that.metaData,_that.httpRequestModel,_that.aiRequestModel,_that.httpResponseModel,_that.preRequestScript,_that.postRequestScript,_that.authModel);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String historyId, HistoryMetaModel metaData, HttpRequestModel? httpRequestModel, AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel) $default,) {final _that = this; +switch (_that) { +case _HistoryRequestModel(): +return $default(_that.historyId,_that.metaData,_that.httpRequestModel,_that.aiRequestModel,_that.httpResponseModel,_that.preRequestScript,_that.postRequestScript,_that.authModel);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String historyId, HistoryMetaModel metaData, HttpRequestModel? httpRequestModel, AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel)? $default,) {final _that = this; +switch (_that) { +case _HistoryRequestModel() when $default != null: +return $default(_that.historyId,_that.metaData,_that.httpRequestModel,_that.aiRequestModel,_that.httpResponseModel,_that.preRequestScript,_that.postRequestScript,_that.authModel);case _: + return null; + +} } -/// @nodoc -class __$$HistoryRequestModelImplCopyWithImpl<$Res> - extends _$HistoryRequestModelCopyWithImpl<$Res, _$HistoryRequestModelImpl> - implements _$$HistoryRequestModelImplCopyWith<$Res> { - __$$HistoryRequestModelImplCopyWithImpl(_$HistoryRequestModelImpl _value, - $Res Function(_$HistoryRequestModelImpl) _then) - : super(_value, _then); - - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? historyId = null, - Object? metaData = null, - Object? httpRequestModel = freezed, - Object? aiRequestModel = freezed, - Object? httpResponseModel = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, - Object? authModel = freezed, - }) { - return _then(_$HistoryRequestModelImpl( - historyId: null == historyId - ? _value.historyId - : historyId // ignore: cast_nullable_to_non_nullable - as String, - metaData: null == metaData - ? _value.metaData - : metaData // ignore: cast_nullable_to_non_nullable - as HistoryMetaModel, - httpRequestModel: freezed == httpRequestModel - ? _value.httpRequestModel - : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel?, - aiRequestModel: freezed == aiRequestModel - ? _value.aiRequestModel - : aiRequestModel // ignore: cast_nullable_to_non_nullable - as AIRequestModel?, - httpResponseModel: null == httpResponseModel - ? _value.httpResponseModel - : httpResponseModel // ignore: cast_nullable_to_non_nullable - as HttpResponseModel, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, - )); - } } /// @nodoc @JsonSerializable(explicitToJson: true, anyMap: true) -class _$HistoryRequestModelImpl implements _HistoryRequestModel { - const _$HistoryRequestModelImpl( - {required this.historyId, - required this.metaData, - this.httpRequestModel, - this.aiRequestModel, - required this.httpResponseModel, - this.preRequestScript, - this.postRequestScript, - this.authModel}); - - factory _$HistoryRequestModelImpl.fromJson(Map json) => - _$$HistoryRequestModelImplFromJson(json); - - @override - final String historyId; - @override - final HistoryMetaModel metaData; - @override - final HttpRequestModel? httpRequestModel; - @override - final AIRequestModel? aiRequestModel; - @override - final HttpResponseModel httpResponseModel; - @override - final String? preRequestScript; - @override - final String? postRequestScript; - @override - final AuthModel? authModel; - - @override - String toString() { - return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, aiRequestModel: $aiRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; +class _HistoryRequestModel implements HistoryRequestModel { + const _HistoryRequestModel({required this.historyId, required this.metaData, this.httpRequestModel, this.aiRequestModel, required this.httpResponseModel, this.preRequestScript, this.postRequestScript, this.authModel}); + factory _HistoryRequestModel.fromJson(Map json) => _$HistoryRequestModelFromJson(json); + +@override final String historyId; +@override final HistoryMetaModel metaData; +@override final HttpRequestModel? httpRequestModel; +@override final AIRequestModel? aiRequestModel; +@override final HttpResponseModel httpResponseModel; +@override final String? preRequestScript; +@override final String? postRequestScript; +@override final AuthModel? authModel; + +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$HistoryRequestModelCopyWith<_HistoryRequestModel> get copyWith => __$HistoryRequestModelCopyWithImpl<_HistoryRequestModel>(this, _$identity); + +@override +Map toJson() { + return _$HistoryRequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _HistoryRequestModel&&(identical(other.historyId, historyId) || other.historyId == historyId)&&(identical(other.metaData, metaData) || other.metaData == metaData)&&(identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel)&&(identical(other.aiRequestModel, aiRequestModel) || other.aiRequestModel == aiRequestModel)&&(identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel)&&(identical(other.preRequestScript, preRequestScript) || other.preRequestScript == preRequestScript)&&(identical(other.postRequestScript, postRequestScript) || other.postRequestScript == postRequestScript)&&(identical(other.authModel, authModel) || other.authModel == authModel)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,historyId,metaData,httpRequestModel,aiRequestModel,httpResponseModel,preRequestScript,postRequestScript,authModel); + +@override +String toString() { + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, aiRequestModel: $aiRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; +} + + +} + +/// @nodoc +abstract mixin class _$HistoryRequestModelCopyWith<$Res> implements $HistoryRequestModelCopyWith<$Res> { + factory _$HistoryRequestModelCopyWith(_HistoryRequestModel value, $Res Function(_HistoryRequestModel) _then) = __$HistoryRequestModelCopyWithImpl; +@override @useResult +$Res call({ + String historyId, HistoryMetaModel metaData, HttpRequestModel? httpRequestModel, AIRequestModel? aiRequestModel, HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, AuthModel? authModel +}); + + +@override $HistoryMetaModelCopyWith<$Res> get metaData;@override $HttpRequestModelCopyWith<$Res>? get httpRequestModel;@override $AIRequestModelCopyWith<$Res>? get aiRequestModel;@override $HttpResponseModelCopyWith<$Res> get httpResponseModel;@override $AuthModelCopyWith<$Res>? get authModel; + +} +/// @nodoc +class __$HistoryRequestModelCopyWithImpl<$Res> + implements _$HistoryRequestModelCopyWith<$Res> { + __$HistoryRequestModelCopyWithImpl(this._self, this._then); + + final _HistoryRequestModel _self; + final $Res Function(_HistoryRequestModel) _then; + +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? historyId = null,Object? metaData = null,Object? httpRequestModel = freezed,Object? aiRequestModel = freezed,Object? httpResponseModel = null,Object? preRequestScript = freezed,Object? postRequestScript = freezed,Object? authModel = freezed,}) { + return _then(_HistoryRequestModel( +historyId: null == historyId ? _self.historyId : historyId // ignore: cast_nullable_to_non_nullable +as String,metaData: null == metaData ? _self.metaData : metaData // ignore: cast_nullable_to_non_nullable +as HistoryMetaModel,httpRequestModel: freezed == httpRequestModel ? _self.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable +as HttpRequestModel?,aiRequestModel: freezed == aiRequestModel ? _self.aiRequestModel : aiRequestModel // ignore: cast_nullable_to_non_nullable +as AIRequestModel?,httpResponseModel: null == httpResponseModel ? _self.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable +as HttpResponseModel,preRequestScript: freezed == preRequestScript ? _self.preRequestScript : preRequestScript // ignore: cast_nullable_to_non_nullable +as String?,postRequestScript: freezed == postRequestScript ? _self.postRequestScript : postRequestScript // ignore: cast_nullable_to_non_nullable +as String?,authModel: freezed == authModel ? _self.authModel : authModel // ignore: cast_nullable_to_non_nullable +as AuthModel?, + )); +} + +/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HistoryMetaModelCopyWith<$Res> get metaData { + + return $HistoryMetaModelCopyWith<$Res>(_self.metaData, (value) { + return _then(_self.copyWith(metaData: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpRequestModelCopyWith<$Res>? get httpRequestModel { + if (_self.httpRequestModel == null) { + return null; } - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$HistoryRequestModelImpl && - (identical(other.historyId, historyId) || - other.historyId == historyId) && - (identical(other.metaData, metaData) || - other.metaData == metaData) && - (identical(other.httpRequestModel, httpRequestModel) || - other.httpRequestModel == httpRequestModel) && - (identical(other.aiRequestModel, aiRequestModel) || - other.aiRequestModel == aiRequestModel) && - (identical(other.httpResponseModel, httpResponseModel) || - other.httpResponseModel == httpResponseModel) && - (identical(other.preRequestScript, preRequestScript) || - other.preRequestScript == preRequestScript) && - (identical(other.postRequestScript, postRequestScript) || - other.postRequestScript == postRequestScript) && - (identical(other.authModel, authModel) || - other.authModel == authModel)); + return $HttpRequestModelCopyWith<$Res>(_self.httpRequestModel!, (value) { + return _then(_self.copyWith(httpRequestModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AIRequestModelCopyWith<$Res>? get aiRequestModel { + if (_self.aiRequestModel == null) { + return null; } - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash( - runtimeType, - historyId, - metaData, - httpRequestModel, - aiRequestModel, - httpResponseModel, - preRequestScript, - postRequestScript, - authModel); - - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$HistoryRequestModelImplCopyWith<_$HistoryRequestModelImpl> get copyWith => - __$$HistoryRequestModelImplCopyWithImpl<_$HistoryRequestModelImpl>( - this, _$identity); - - @override - Map toJson() { - return _$$HistoryRequestModelImplToJson( - this, - ); + return $AIRequestModelCopyWith<$Res>(_self.aiRequestModel!, (value) { + return _then(_self.copyWith(aiRequestModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpResponseModelCopyWith<$Res> get httpResponseModel { + + return $HttpResponseModelCopyWith<$Res>(_self.httpResponseModel, (value) { + return _then(_self.copyWith(httpResponseModel: value)); + }); +}/// Create a copy of HistoryRequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AuthModelCopyWith<$Res>? get authModel { + if (_self.authModel == null) { + return null; } -} -abstract class _HistoryRequestModel implements HistoryRequestModel { - const factory _HistoryRequestModel( - {required final String historyId, - required final HistoryMetaModel metaData, - final HttpRequestModel? httpRequestModel, - final AIRequestModel? aiRequestModel, - required final HttpResponseModel httpResponseModel, - final String? preRequestScript, - final String? postRequestScript, - final AuthModel? authModel}) = _$HistoryRequestModelImpl; - - factory _HistoryRequestModel.fromJson(Map json) = - _$HistoryRequestModelImpl.fromJson; - - @override - String get historyId; - @override - HistoryMetaModel get metaData; - @override - HttpRequestModel? get httpRequestModel; - @override - AIRequestModel? get aiRequestModel; - @override - HttpResponseModel get httpResponseModel; - @override - String? get preRequestScript; - @override - String? get postRequestScript; - @override - AuthModel? get authModel; - - /// Create a copy of HistoryRequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$HistoryRequestModelImplCopyWith<_$HistoryRequestModelImpl> get copyWith => - throw _privateConstructorUsedError; + return $AuthModelCopyWith<$Res>(_self.authModel!, (value) { + return _then(_self.copyWith(authModel: value)); + }); +} } + +// dart format on diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index 2548ce76a6..2937eb13ba 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -6,38 +6,43 @@ part of 'history_request_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => - _$HistoryRequestModelImpl( +_HistoryRequestModel _$HistoryRequestModelFromJson(Map json) => + _HistoryRequestModel( historyId: json['historyId'] as String, metaData: HistoryMetaModel.fromJson( - Map.from(json['metaData'] as Map)), + Map.from(json['metaData'] as Map), + ), httpRequestModel: json['httpRequestModel'] == null ? null : HttpRequestModel.fromJson( - Map.from(json['httpRequestModel'] as Map)), + Map.from(json['httpRequestModel'] as Map), + ), aiRequestModel: json['aiRequestModel'] == null ? null : AIRequestModel.fromJson( - Map.from(json['aiRequestModel'] as Map)), + Map.from(json['aiRequestModel'] as Map), + ), httpResponseModel: HttpResponseModel.fromJson( - Map.from(json['httpResponseModel'] as Map)), + Map.from(json['httpResponseModel'] as Map), + ), preRequestScript: json['preRequestScript'] as String?, postRequestScript: json['postRequestScript'] as String?, authModel: json['authModel'] == null ? null : AuthModel.fromJson( - Map.from(json['authModel'] as Map)), + Map.from(json['authModel'] as Map), + ), ); -Map _$$HistoryRequestModelImplToJson( - _$HistoryRequestModelImpl instance) => - { - 'historyId': instance.historyId, - 'metaData': instance.metaData.toJson(), - 'httpRequestModel': instance.httpRequestModel?.toJson(), - 'aiRequestModel': instance.aiRequestModel?.toJson(), - 'httpResponseModel': instance.httpResponseModel.toJson(), - 'preRequestScript': instance.preRequestScript, - 'postRequestScript': instance.postRequestScript, - 'authModel': instance.authModel?.toJson(), - }; +Map _$HistoryRequestModelToJson( + _HistoryRequestModel instance, +) => { + 'historyId': instance.historyId, + 'metaData': instance.metaData.toJson(), + 'httpRequestModel': instance.httpRequestModel?.toJson(), + 'aiRequestModel': instance.aiRequestModel?.toJson(), + 'httpResponseModel': instance.httpResponseModel.toJson(), + 'preRequestScript': instance.preRequestScript, + 'postRequestScript': instance.postRequestScript, + 'authModel': instance.authModel?.toJson(), +}; diff --git a/lib/models/protocols/base_protocol_model.dart b/lib/models/protocols/base_protocol_model.dart new file mode 100644 index 0000000000..ccb880b758 --- /dev/null +++ b/lib/models/protocols/base_protocol_model.dart @@ -0,0 +1,65 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'websocket_model.dart'; +import 'mqtt_model.dart'; +import 'grpc_model.dart'; + +/// Abstract base class for all protocol-specific request models. +abstract class ProtocolModel {} + +/// Polymorphic converter for [ProtocolModel] to handle JSON serialization. +class ProtocolModelConverter implements JsonConverter { + const ProtocolModelConverter(); + + @override + ProtocolModel? fromJson(dynamic jsonInput) { + if (jsonInput == null || jsonInput is! Map) return null; + final json = Map.from(jsonInput); + final typeStr = json['type'] as String?; + if (typeStr == APIType.websocket.name) { + return WebSocketRequestModel.fromJson(json); + } else if (typeStr == APIType.mqtt.name) { + return MQTTRequestModel.fromJson(json); + } else if (typeStr == APIType.grpc.name) { + return GrpcRequestModel.fromJson(json); + } + + // Fallback + if (json.containsKey('brokerUrl')) { + return MQTTRequestModel.fromJson(json); + } + if (json.containsKey('url') && json.containsKey('autoReconnect')) { + return WebSocketRequestModel.fromJson(json); + } + if (json.containsKey('host') && + json.containsKey('port') && + !json.containsKey('brokerUrl')) { + return GrpcRequestModel.fromJson(json); + } + + return null; + } + + @override + Map? toJson(ProtocolModel? object) { + if (object == null) return null; + Map? json; + String? type; + + if (object is WebSocketRequestModel) { + json = object.toJson(); + type = APIType.websocket.name; + } else if (object is MQTTRequestModel) { + json = object.toJson(); + type = APIType.mqtt.name; + } else if (object is GrpcRequestModel) { + json = object.toJson(); + type = APIType.grpc.name; + } + + if (json != null && type != null) { + return {...json, 'type': type}; + } + + return json; + } +} diff --git a/lib/models/protocols/grpc_model.dart b/lib/models/protocols/grpc_model.dart new file mode 100644 index 0000000000..b77fa04450 --- /dev/null +++ b/lib/models/protocols/grpc_model.dart @@ -0,0 +1,59 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/models/protocols/base_protocol_model.dart'; +import 'websocket_model.dart'; + +part 'grpc_model.freezed.dart'; +part 'grpc_model.g.dart'; + +enum GrpcStreamingType { unary, client, server, bidi } + +@freezed +abstract class GrpcParameterModel with _$GrpcParameterModel { + const factory GrpcParameterModel({ + required String name, + int? tag, + @Default("string") String type, + @Default("") String value, + @Default(true) bool enabled, + List? enumValues, + }) = _GrpcParameterModel; + + factory GrpcParameterModel.fromJson(Map json) => + _$GrpcParameterModelFromJson(json); +} + +@freezed +abstract class GrpcRequestModel + with _$GrpcRequestModel + implements ProtocolModel { + const GrpcRequestModel._(); + + const factory GrpcRequestModel({ + required String host, + @Default(50051) int port, + String? service, + String? method, + String? protoFile, + @Default(false) bool useTLS, + @Default(GrpcStreamingType.unary) GrpcStreamingType streamingType, + @Default([]) List messageHistory, + @Default("") String requestBody, + @Default(false) bool useReflection, + @Default([]) List? metadata, + @Default([]) List? isMetadataEnabled, + @Default([]) List availableServices, + @Default([]) List availableMethods, + @Default([]) List parameters, + }) = _GrpcRequestModel; + + Map get metadataMap { + if (metadata == null) return {}; + return { + for (var m in (metadata!)) + if (m.name.isNotEmpty) m.name: m.value + }; + } + + factory GrpcRequestModel.fromJson(Map json) => + _$GrpcRequestModelFromJson(json); +} diff --git a/lib/models/protocols/grpc_model.freezed.dart b/lib/models/protocols/grpc_model.freezed.dart new file mode 100644 index 0000000000..035cd1d745 --- /dev/null +++ b/lib/models/protocols/grpc_model.freezed.dart @@ -0,0 +1,645 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'grpc_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$GrpcParameterModel { + + String get name; int? get tag; String get type; String get value; bool get enabled; List? get enumValues; +/// Create a copy of GrpcParameterModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$GrpcParameterModelCopyWith get copyWith => _$GrpcParameterModelCopyWithImpl(this as GrpcParameterModel, _$identity); + + /// Serializes this GrpcParameterModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is GrpcParameterModel&&(identical(other.name, name) || other.name == name)&&(identical(other.tag, tag) || other.tag == tag)&&(identical(other.type, type) || other.type == type)&&(identical(other.value, value) || other.value == value)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&const DeepCollectionEquality().equals(other.enumValues, enumValues)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,name,tag,type,value,enabled,const DeepCollectionEquality().hash(enumValues)); + +@override +String toString() { + return 'GrpcParameterModel(name: $name, tag: $tag, type: $type, value: $value, enabled: $enabled, enumValues: $enumValues)'; +} + + +} + +/// @nodoc +abstract mixin class $GrpcParameterModelCopyWith<$Res> { + factory $GrpcParameterModelCopyWith(GrpcParameterModel value, $Res Function(GrpcParameterModel) _then) = _$GrpcParameterModelCopyWithImpl; +@useResult +$Res call({ + String name, int? tag, String type, String value, bool enabled, List? enumValues +}); + + + + +} +/// @nodoc +class _$GrpcParameterModelCopyWithImpl<$Res> + implements $GrpcParameterModelCopyWith<$Res> { + _$GrpcParameterModelCopyWithImpl(this._self, this._then); + + final GrpcParameterModel _self; + final $Res Function(GrpcParameterModel) _then; + +/// Create a copy of GrpcParameterModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? name = null,Object? tag = freezed,Object? type = null,Object? value = null,Object? enabled = null,Object? enumValues = freezed,}) { + return _then(_self.copyWith( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,tag: freezed == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable +as int?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String,value: null == value ? _self.value : value // ignore: cast_nullable_to_non_nullable +as String,enabled: null == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable +as bool,enumValues: freezed == enumValues ? _self.enumValues : enumValues // ignore: cast_nullable_to_non_nullable +as List?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [GrpcParameterModel]. +extension GrpcParameterModelPatterns on GrpcParameterModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _GrpcParameterModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _GrpcParameterModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _GrpcParameterModel value) $default,){ +final _that = this; +switch (_that) { +case _GrpcParameterModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _GrpcParameterModel value)? $default,){ +final _that = this; +switch (_that) { +case _GrpcParameterModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String name, int? tag, String type, String value, bool enabled, List? enumValues)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _GrpcParameterModel() when $default != null: +return $default(_that.name,_that.tag,_that.type,_that.value,_that.enabled,_that.enumValues);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String name, int? tag, String type, String value, bool enabled, List? enumValues) $default,) {final _that = this; +switch (_that) { +case _GrpcParameterModel(): +return $default(_that.name,_that.tag,_that.type,_that.value,_that.enabled,_that.enumValues);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String name, int? tag, String type, String value, bool enabled, List? enumValues)? $default,) {final _that = this; +switch (_that) { +case _GrpcParameterModel() when $default != null: +return $default(_that.name,_that.tag,_that.type,_that.value,_that.enabled,_that.enumValues);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _GrpcParameterModel implements GrpcParameterModel { + const _GrpcParameterModel({required this.name, this.tag, this.type = "string", this.value = "", this.enabled = true, final List? enumValues}): _enumValues = enumValues; + factory _GrpcParameterModel.fromJson(Map json) => _$GrpcParameterModelFromJson(json); + +@override final String name; +@override final int? tag; +@override@JsonKey() final String type; +@override@JsonKey() final String value; +@override@JsonKey() final bool enabled; + final List? _enumValues; +@override List? get enumValues { + final value = _enumValues; + if (value == null) return null; + if (_enumValues is EqualUnmodifiableListView) return _enumValues; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + +/// Create a copy of GrpcParameterModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$GrpcParameterModelCopyWith<_GrpcParameterModel> get copyWith => __$GrpcParameterModelCopyWithImpl<_GrpcParameterModel>(this, _$identity); + +@override +Map toJson() { + return _$GrpcParameterModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _GrpcParameterModel&&(identical(other.name, name) || other.name == name)&&(identical(other.tag, tag) || other.tag == tag)&&(identical(other.type, type) || other.type == type)&&(identical(other.value, value) || other.value == value)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&const DeepCollectionEquality().equals(other._enumValues, _enumValues)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,name,tag,type,value,enabled,const DeepCollectionEquality().hash(_enumValues)); + +@override +String toString() { + return 'GrpcParameterModel(name: $name, tag: $tag, type: $type, value: $value, enabled: $enabled, enumValues: $enumValues)'; +} + + +} + +/// @nodoc +abstract mixin class _$GrpcParameterModelCopyWith<$Res> implements $GrpcParameterModelCopyWith<$Res> { + factory _$GrpcParameterModelCopyWith(_GrpcParameterModel value, $Res Function(_GrpcParameterModel) _then) = __$GrpcParameterModelCopyWithImpl; +@override @useResult +$Res call({ + String name, int? tag, String type, String value, bool enabled, List? enumValues +}); + + + + +} +/// @nodoc +class __$GrpcParameterModelCopyWithImpl<$Res> + implements _$GrpcParameterModelCopyWith<$Res> { + __$GrpcParameterModelCopyWithImpl(this._self, this._then); + + final _GrpcParameterModel _self; + final $Res Function(_GrpcParameterModel) _then; + +/// Create a copy of GrpcParameterModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? name = null,Object? tag = freezed,Object? type = null,Object? value = null,Object? enabled = null,Object? enumValues = freezed,}) { + return _then(_GrpcParameterModel( +name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,tag: freezed == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable +as int?,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String,value: null == value ? _self.value : value // ignore: cast_nullable_to_non_nullable +as String,enabled: null == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable +as bool,enumValues: freezed == enumValues ? _self._enumValues : enumValues // ignore: cast_nullable_to_non_nullable +as List?, + )); +} + + +} + + +/// @nodoc +mixin _$GrpcRequestModel { + + String get host; int get port; String? get service; String? get method; String? get protoFile; bool get useTLS; GrpcStreamingType get streamingType; List get messageHistory; String get requestBody; bool get useReflection; List? get metadata; List? get isMetadataEnabled; List get availableServices; List get availableMethods; List get parameters; +/// Create a copy of GrpcRequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$GrpcRequestModelCopyWith get copyWith => _$GrpcRequestModelCopyWithImpl(this as GrpcRequestModel, _$identity); + + /// Serializes this GrpcRequestModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is GrpcRequestModel&&(identical(other.host, host) || other.host == host)&&(identical(other.port, port) || other.port == port)&&(identical(other.service, service) || other.service == service)&&(identical(other.method, method) || other.method == method)&&(identical(other.protoFile, protoFile) || other.protoFile == protoFile)&&(identical(other.useTLS, useTLS) || other.useTLS == useTLS)&&(identical(other.streamingType, streamingType) || other.streamingType == streamingType)&&const DeepCollectionEquality().equals(other.messageHistory, messageHistory)&&(identical(other.requestBody, requestBody) || other.requestBody == requestBody)&&(identical(other.useReflection, useReflection) || other.useReflection == useReflection)&&const DeepCollectionEquality().equals(other.metadata, metadata)&&const DeepCollectionEquality().equals(other.isMetadataEnabled, isMetadataEnabled)&&const DeepCollectionEquality().equals(other.availableServices, availableServices)&&const DeepCollectionEquality().equals(other.availableMethods, availableMethods)&&const DeepCollectionEquality().equals(other.parameters, parameters)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,host,port,service,method,protoFile,useTLS,streamingType,const DeepCollectionEquality().hash(messageHistory),requestBody,useReflection,const DeepCollectionEquality().hash(metadata),const DeepCollectionEquality().hash(isMetadataEnabled),const DeepCollectionEquality().hash(availableServices),const DeepCollectionEquality().hash(availableMethods),const DeepCollectionEquality().hash(parameters)); + +@override +String toString() { + return 'GrpcRequestModel(host: $host, port: $port, service: $service, method: $method, protoFile: $protoFile, useTLS: $useTLS, streamingType: $streamingType, messageHistory: $messageHistory, requestBody: $requestBody, useReflection: $useReflection, metadata: $metadata, isMetadataEnabled: $isMetadataEnabled, availableServices: $availableServices, availableMethods: $availableMethods, parameters: $parameters)'; +} + + +} + +/// @nodoc +abstract mixin class $GrpcRequestModelCopyWith<$Res> { + factory $GrpcRequestModelCopyWith(GrpcRequestModel value, $Res Function(GrpcRequestModel) _then) = _$GrpcRequestModelCopyWithImpl; +@useResult +$Res call({ + String host, int port, String? service, String? method, String? protoFile, bool useTLS, GrpcStreamingType streamingType, List messageHistory, String requestBody, bool useReflection, List? metadata, List? isMetadataEnabled, List availableServices, List availableMethods, List parameters +}); + + + + +} +/// @nodoc +class _$GrpcRequestModelCopyWithImpl<$Res> + implements $GrpcRequestModelCopyWith<$Res> { + _$GrpcRequestModelCopyWithImpl(this._self, this._then); + + final GrpcRequestModel _self; + final $Res Function(GrpcRequestModel) _then; + +/// Create a copy of GrpcRequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? host = null,Object? port = null,Object? service = freezed,Object? method = freezed,Object? protoFile = freezed,Object? useTLS = null,Object? streamingType = null,Object? messageHistory = null,Object? requestBody = null,Object? useReflection = null,Object? metadata = freezed,Object? isMetadataEnabled = freezed,Object? availableServices = null,Object? availableMethods = null,Object? parameters = null,}) { + return _then(_self.copyWith( +host: null == host ? _self.host : host // ignore: cast_nullable_to_non_nullable +as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable +as int,service: freezed == service ? _self.service : service // ignore: cast_nullable_to_non_nullable +as String?,method: freezed == method ? _self.method : method // ignore: cast_nullable_to_non_nullable +as String?,protoFile: freezed == protoFile ? _self.protoFile : protoFile // ignore: cast_nullable_to_non_nullable +as String?,useTLS: null == useTLS ? _self.useTLS : useTLS // ignore: cast_nullable_to_non_nullable +as bool,streamingType: null == streamingType ? _self.streamingType : streamingType // ignore: cast_nullable_to_non_nullable +as GrpcStreamingType,messageHistory: null == messageHistory ? _self.messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,requestBody: null == requestBody ? _self.requestBody : requestBody // ignore: cast_nullable_to_non_nullable +as String,useReflection: null == useReflection ? _self.useReflection : useReflection // ignore: cast_nullable_to_non_nullable +as bool,metadata: freezed == metadata ? _self.metadata : metadata // ignore: cast_nullable_to_non_nullable +as List?,isMetadataEnabled: freezed == isMetadataEnabled ? _self.isMetadataEnabled : isMetadataEnabled // ignore: cast_nullable_to_non_nullable +as List?,availableServices: null == availableServices ? _self.availableServices : availableServices // ignore: cast_nullable_to_non_nullable +as List,availableMethods: null == availableMethods ? _self.availableMethods : availableMethods // ignore: cast_nullable_to_non_nullable +as List,parameters: null == parameters ? _self.parameters : parameters // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +} + + +/// Adds pattern-matching-related methods to [GrpcRequestModel]. +extension GrpcRequestModelPatterns on GrpcRequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _GrpcRequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _GrpcRequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _GrpcRequestModel value) $default,){ +final _that = this; +switch (_that) { +case _GrpcRequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _GrpcRequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _GrpcRequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String host, int port, String? service, String? method, String? protoFile, bool useTLS, GrpcStreamingType streamingType, List messageHistory, String requestBody, bool useReflection, List? metadata, List? isMetadataEnabled, List availableServices, List availableMethods, List parameters)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _GrpcRequestModel() when $default != null: +return $default(_that.host,_that.port,_that.service,_that.method,_that.protoFile,_that.useTLS,_that.streamingType,_that.messageHistory,_that.requestBody,_that.useReflection,_that.metadata,_that.isMetadataEnabled,_that.availableServices,_that.availableMethods,_that.parameters);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String host, int port, String? service, String? method, String? protoFile, bool useTLS, GrpcStreamingType streamingType, List messageHistory, String requestBody, bool useReflection, List? metadata, List? isMetadataEnabled, List availableServices, List availableMethods, List parameters) $default,) {final _that = this; +switch (_that) { +case _GrpcRequestModel(): +return $default(_that.host,_that.port,_that.service,_that.method,_that.protoFile,_that.useTLS,_that.streamingType,_that.messageHistory,_that.requestBody,_that.useReflection,_that.metadata,_that.isMetadataEnabled,_that.availableServices,_that.availableMethods,_that.parameters);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String host, int port, String? service, String? method, String? protoFile, bool useTLS, GrpcStreamingType streamingType, List messageHistory, String requestBody, bool useReflection, List? metadata, List? isMetadataEnabled, List availableServices, List availableMethods, List parameters)? $default,) {final _that = this; +switch (_that) { +case _GrpcRequestModel() when $default != null: +return $default(_that.host,_that.port,_that.service,_that.method,_that.protoFile,_that.useTLS,_that.streamingType,_that.messageHistory,_that.requestBody,_that.useReflection,_that.metadata,_that.isMetadataEnabled,_that.availableServices,_that.availableMethods,_that.parameters);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _GrpcRequestModel extends GrpcRequestModel { + const _GrpcRequestModel({required this.host, this.port = 50051, this.service, this.method, this.protoFile, this.useTLS = false, this.streamingType = GrpcStreamingType.unary, final List messageHistory = const [], this.requestBody = "", this.useReflection = false, final List? metadata = const [], final List? isMetadataEnabled = const [], final List availableServices = const [], final List availableMethods = const [], final List parameters = const []}): _messageHistory = messageHistory,_metadata = metadata,_isMetadataEnabled = isMetadataEnabled,_availableServices = availableServices,_availableMethods = availableMethods,_parameters = parameters,super._(); + factory _GrpcRequestModel.fromJson(Map json) => _$GrpcRequestModelFromJson(json); + +@override final String host; +@override@JsonKey() final int port; +@override final String? service; +@override final String? method; +@override final String? protoFile; +@override@JsonKey() final bool useTLS; +@override@JsonKey() final GrpcStreamingType streamingType; + final List _messageHistory; +@override@JsonKey() List get messageHistory { + if (_messageHistory is EqualUnmodifiableListView) return _messageHistory; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_messageHistory); +} + +@override@JsonKey() final String requestBody; +@override@JsonKey() final bool useReflection; + final List? _metadata; +@override@JsonKey() List? get metadata { + final value = _metadata; + if (value == null) return null; + if (_metadata is EqualUnmodifiableListView) return _metadata; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List? _isMetadataEnabled; +@override@JsonKey() List? get isMetadataEnabled { + final value = _isMetadataEnabled; + if (value == null) return null; + if (_isMetadataEnabled is EqualUnmodifiableListView) return _isMetadataEnabled; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List _availableServices; +@override@JsonKey() List get availableServices { + if (_availableServices is EqualUnmodifiableListView) return _availableServices; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_availableServices); +} + + final List _availableMethods; +@override@JsonKey() List get availableMethods { + if (_availableMethods is EqualUnmodifiableListView) return _availableMethods; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_availableMethods); +} + + final List _parameters; +@override@JsonKey() List get parameters { + if (_parameters is EqualUnmodifiableListView) return _parameters; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_parameters); +} + + +/// Create a copy of GrpcRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$GrpcRequestModelCopyWith<_GrpcRequestModel> get copyWith => __$GrpcRequestModelCopyWithImpl<_GrpcRequestModel>(this, _$identity); + +@override +Map toJson() { + return _$GrpcRequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _GrpcRequestModel&&(identical(other.host, host) || other.host == host)&&(identical(other.port, port) || other.port == port)&&(identical(other.service, service) || other.service == service)&&(identical(other.method, method) || other.method == method)&&(identical(other.protoFile, protoFile) || other.protoFile == protoFile)&&(identical(other.useTLS, useTLS) || other.useTLS == useTLS)&&(identical(other.streamingType, streamingType) || other.streamingType == streamingType)&&const DeepCollectionEquality().equals(other._messageHistory, _messageHistory)&&(identical(other.requestBody, requestBody) || other.requestBody == requestBody)&&(identical(other.useReflection, useReflection) || other.useReflection == useReflection)&&const DeepCollectionEquality().equals(other._metadata, _metadata)&&const DeepCollectionEquality().equals(other._isMetadataEnabled, _isMetadataEnabled)&&const DeepCollectionEquality().equals(other._availableServices, _availableServices)&&const DeepCollectionEquality().equals(other._availableMethods, _availableMethods)&&const DeepCollectionEquality().equals(other._parameters, _parameters)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,host,port,service,method,protoFile,useTLS,streamingType,const DeepCollectionEquality().hash(_messageHistory),requestBody,useReflection,const DeepCollectionEquality().hash(_metadata),const DeepCollectionEquality().hash(_isMetadataEnabled),const DeepCollectionEquality().hash(_availableServices),const DeepCollectionEquality().hash(_availableMethods),const DeepCollectionEquality().hash(_parameters)); + +@override +String toString() { + return 'GrpcRequestModel(host: $host, port: $port, service: $service, method: $method, protoFile: $protoFile, useTLS: $useTLS, streamingType: $streamingType, messageHistory: $messageHistory, requestBody: $requestBody, useReflection: $useReflection, metadata: $metadata, isMetadataEnabled: $isMetadataEnabled, availableServices: $availableServices, availableMethods: $availableMethods, parameters: $parameters)'; +} + + +} + +/// @nodoc +abstract mixin class _$GrpcRequestModelCopyWith<$Res> implements $GrpcRequestModelCopyWith<$Res> { + factory _$GrpcRequestModelCopyWith(_GrpcRequestModel value, $Res Function(_GrpcRequestModel) _then) = __$GrpcRequestModelCopyWithImpl; +@override @useResult +$Res call({ + String host, int port, String? service, String? method, String? protoFile, bool useTLS, GrpcStreamingType streamingType, List messageHistory, String requestBody, bool useReflection, List? metadata, List? isMetadataEnabled, List availableServices, List availableMethods, List parameters +}); + + + + +} +/// @nodoc +class __$GrpcRequestModelCopyWithImpl<$Res> + implements _$GrpcRequestModelCopyWith<$Res> { + __$GrpcRequestModelCopyWithImpl(this._self, this._then); + + final _GrpcRequestModel _self; + final $Res Function(_GrpcRequestModel) _then; + +/// Create a copy of GrpcRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? host = null,Object? port = null,Object? service = freezed,Object? method = freezed,Object? protoFile = freezed,Object? useTLS = null,Object? streamingType = null,Object? messageHistory = null,Object? requestBody = null,Object? useReflection = null,Object? metadata = freezed,Object? isMetadataEnabled = freezed,Object? availableServices = null,Object? availableMethods = null,Object? parameters = null,}) { + return _then(_GrpcRequestModel( +host: null == host ? _self.host : host // ignore: cast_nullable_to_non_nullable +as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable +as int,service: freezed == service ? _self.service : service // ignore: cast_nullable_to_non_nullable +as String?,method: freezed == method ? _self.method : method // ignore: cast_nullable_to_non_nullable +as String?,protoFile: freezed == protoFile ? _self.protoFile : protoFile // ignore: cast_nullable_to_non_nullable +as String?,useTLS: null == useTLS ? _self.useTLS : useTLS // ignore: cast_nullable_to_non_nullable +as bool,streamingType: null == streamingType ? _self.streamingType : streamingType // ignore: cast_nullable_to_non_nullable +as GrpcStreamingType,messageHistory: null == messageHistory ? _self._messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,requestBody: null == requestBody ? _self.requestBody : requestBody // ignore: cast_nullable_to_non_nullable +as String,useReflection: null == useReflection ? _self.useReflection : useReflection // ignore: cast_nullable_to_non_nullable +as bool,metadata: freezed == metadata ? _self._metadata : metadata // ignore: cast_nullable_to_non_nullable +as List?,isMetadataEnabled: freezed == isMetadataEnabled ? _self._isMetadataEnabled : isMetadataEnabled // ignore: cast_nullable_to_non_nullable +as List?,availableServices: null == availableServices ? _self._availableServices : availableServices // ignore: cast_nullable_to_non_nullable +as List,availableMethods: null == availableMethods ? _self._availableMethods : availableMethods // ignore: cast_nullable_to_non_nullable +as List,parameters: null == parameters ? _self._parameters : parameters // ignore: cast_nullable_to_non_nullable +as List, + )); +} + + +} + +// dart format on diff --git a/lib/models/protocols/grpc_model.g.dart b/lib/models/protocols/grpc_model.g.dart new file mode 100644 index 0000000000..f50085bce7 --- /dev/null +++ b/lib/models/protocols/grpc_model.g.dart @@ -0,0 +1,101 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'grpc_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_GrpcParameterModel _$GrpcParameterModelFromJson(Map json) => + _GrpcParameterModel( + name: json['name'] as String, + tag: (json['tag'] as num?)?.toInt(), + type: json['type'] as String? ?? "string", + value: json['value'] as String? ?? "", + enabled: json['enabled'] as bool? ?? true, + enumValues: (json['enumValues'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$GrpcParameterModelToJson(_GrpcParameterModel instance) => + { + 'name': instance.name, + 'tag': instance.tag, + 'type': instance.type, + 'value': instance.value, + 'enabled': instance.enabled, + 'enumValues': instance.enumValues, + }; + +_GrpcRequestModel _$GrpcRequestModelFromJson( + Map json, +) => _GrpcRequestModel( + host: json['host'] as String, + port: (json['port'] as num?)?.toInt() ?? 50051, + service: json['service'] as String?, + method: json['method'] as String?, + protoFile: json['protoFile'] as String?, + useTLS: json['useTLS'] as bool? ?? false, + streamingType: + $enumDecodeNullable(_$GrpcStreamingTypeEnumMap, json['streamingType']) ?? + GrpcStreamingType.unary, + messageHistory: + (json['messageHistory'] as List?) + ?.map((e) => WebSocketMessage.fromJson(e as Map)) + .toList() ?? + const [], + requestBody: json['requestBody'] as String? ?? "", + useReflection: json['useReflection'] as bool? ?? false, + metadata: + (json['metadata'] as List?) + ?.map((e) => NameValueModel.fromJson(e as Map)) + .toList() ?? + const [], + isMetadataEnabled: + (json['isMetadataEnabled'] as List?) + ?.map((e) => e as bool) + .toList() ?? + const [], + availableServices: + (json['availableServices'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + availableMethods: + (json['availableMethods'] as List?) + ?.map((e) => e as String) + .toList() ?? + const [], + parameters: + (json['parameters'] as List?) + ?.map((e) => GrpcParameterModel.fromJson(e as Map)) + .toList() ?? + const [], +); + +Map _$GrpcRequestModelToJson(_GrpcRequestModel instance) => + { + 'host': instance.host, + 'port': instance.port, + 'service': instance.service, + 'method': instance.method, + 'protoFile': instance.protoFile, + 'useTLS': instance.useTLS, + 'streamingType': _$GrpcStreamingTypeEnumMap[instance.streamingType]!, + 'messageHistory': instance.messageHistory, + 'requestBody': instance.requestBody, + 'useReflection': instance.useReflection, + 'metadata': instance.metadata, + 'isMetadataEnabled': instance.isMetadataEnabled, + 'availableServices': instance.availableServices, + 'availableMethods': instance.availableMethods, + 'parameters': instance.parameters, + }; + +const _$GrpcStreamingTypeEnumMap = { + GrpcStreamingType.unary: 'unary', + GrpcStreamingType.client: 'client', + GrpcStreamingType.server: 'server', + GrpcStreamingType.bidi: 'bidi', +}; diff --git a/lib/models/protocols/mqtt_model.dart b/lib/models/protocols/mqtt_model.dart new file mode 100644 index 0000000000..fb5aa30764 --- /dev/null +++ b/lib/models/protocols/mqtt_model.dart @@ -0,0 +1,35 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/models/protocols/base_protocol_model.dart'; +import 'websocket_model.dart'; + +part 'mqtt_model.freezed.dart'; +part 'mqtt_model.g.dart'; + +@freezed +abstract class MQTTRequestModel + with _$MQTTRequestModel + implements ProtocolModel { + const factory MQTTRequestModel({ + required String brokerUrl, + @Default(1883) int port, + String? clientId, + String? username, + String? password, + @Default(MQTTVersion.v5) MQTTVersion version, + @Default([]) List subscribedTopics, + @Default([]) List isTopicEnabledList, + @Default(false) bool useTLS, + @Default(false) bool useWebSocket, + @Default(0) int qos, + @Default([]) List messageHistory, + @Default("") String message, + @Default("") String publishTopic, + }) = _MQTTRequestModel; + + factory MQTTRequestModel.fromJson(Map json) => + _$MQTTRequestModelFromJson(json); +} + +/// Enum for MQTT version support. +enum MQTTVersion { v3, v3_1_1, v5 } diff --git a/lib/models/protocols/mqtt_model.freezed.dart b/lib/models/protocols/mqtt_model.freezed.dart new file mode 100644 index 0000000000..513d6f1ab2 --- /dev/null +++ b/lib/models/protocols/mqtt_model.freezed.dart @@ -0,0 +1,334 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'mqtt_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$MQTTRequestModel { + + String get brokerUrl; int get port; String? get clientId; String? get username; String? get password; MQTTVersion get version; List get subscribedTopics; List get isTopicEnabledList; bool get useTLS; bool get useWebSocket; int get qos; List get messageHistory; String get message; String get publishTopic; +/// Create a copy of MQTTRequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$MQTTRequestModelCopyWith get copyWith => _$MQTTRequestModelCopyWithImpl(this as MQTTRequestModel, _$identity); + + /// Serializes this MQTTRequestModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is MQTTRequestModel&&(identical(other.brokerUrl, brokerUrl) || other.brokerUrl == brokerUrl)&&(identical(other.port, port) || other.port == port)&&(identical(other.clientId, clientId) || other.clientId == clientId)&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.version, version) || other.version == version)&&const DeepCollectionEquality().equals(other.subscribedTopics, subscribedTopics)&&const DeepCollectionEquality().equals(other.isTopicEnabledList, isTopicEnabledList)&&(identical(other.useTLS, useTLS) || other.useTLS == useTLS)&&(identical(other.useWebSocket, useWebSocket) || other.useWebSocket == useWebSocket)&&(identical(other.qos, qos) || other.qos == qos)&&const DeepCollectionEquality().equals(other.messageHistory, messageHistory)&&(identical(other.message, message) || other.message == message)&&(identical(other.publishTopic, publishTopic) || other.publishTopic == publishTopic)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,brokerUrl,port,clientId,username,password,version,const DeepCollectionEquality().hash(subscribedTopics),const DeepCollectionEquality().hash(isTopicEnabledList),useTLS,useWebSocket,qos,const DeepCollectionEquality().hash(messageHistory),message,publishTopic); + +@override +String toString() { + return 'MQTTRequestModel(brokerUrl: $brokerUrl, port: $port, clientId: $clientId, username: $username, password: $password, version: $version, subscribedTopics: $subscribedTopics, isTopicEnabledList: $isTopicEnabledList, useTLS: $useTLS, useWebSocket: $useWebSocket, qos: $qos, messageHistory: $messageHistory, message: $message, publishTopic: $publishTopic)'; +} + + +} + +/// @nodoc +abstract mixin class $MQTTRequestModelCopyWith<$Res> { + factory $MQTTRequestModelCopyWith(MQTTRequestModel value, $Res Function(MQTTRequestModel) _then) = _$MQTTRequestModelCopyWithImpl; +@useResult +$Res call({ + String brokerUrl, int port, String? clientId, String? username, String? password, MQTTVersion version, List subscribedTopics, List isTopicEnabledList, bool useTLS, bool useWebSocket, int qos, List messageHistory, String message, String publishTopic +}); + + + + +} +/// @nodoc +class _$MQTTRequestModelCopyWithImpl<$Res> + implements $MQTTRequestModelCopyWith<$Res> { + _$MQTTRequestModelCopyWithImpl(this._self, this._then); + + final MQTTRequestModel _self; + final $Res Function(MQTTRequestModel) _then; + +/// Create a copy of MQTTRequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? brokerUrl = null,Object? port = null,Object? clientId = freezed,Object? username = freezed,Object? password = freezed,Object? version = null,Object? subscribedTopics = null,Object? isTopicEnabledList = null,Object? useTLS = null,Object? useWebSocket = null,Object? qos = null,Object? messageHistory = null,Object? message = null,Object? publishTopic = null,}) { + return _then(_self.copyWith( +brokerUrl: null == brokerUrl ? _self.brokerUrl : brokerUrl // ignore: cast_nullable_to_non_nullable +as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable +as int,clientId: freezed == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable +as String?,username: freezed == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String?,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable +as MQTTVersion,subscribedTopics: null == subscribedTopics ? _self.subscribedTopics : subscribedTopics // ignore: cast_nullable_to_non_nullable +as List,isTopicEnabledList: null == isTopicEnabledList ? _self.isTopicEnabledList : isTopicEnabledList // ignore: cast_nullable_to_non_nullable +as List,useTLS: null == useTLS ? _self.useTLS : useTLS // ignore: cast_nullable_to_non_nullable +as bool,useWebSocket: null == useWebSocket ? _self.useWebSocket : useWebSocket // ignore: cast_nullable_to_non_nullable +as bool,qos: null == qos ? _self.qos : qos // ignore: cast_nullable_to_non_nullable +as int,messageHistory: null == messageHistory ? _self.messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,publishTopic: null == publishTopic ? _self.publishTopic : publishTopic // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [MQTTRequestModel]. +extension MQTTRequestModelPatterns on MQTTRequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _MQTTRequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _MQTTRequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _MQTTRequestModel value) $default,){ +final _that = this; +switch (_that) { +case _MQTTRequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _MQTTRequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _MQTTRequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String brokerUrl, int port, String? clientId, String? username, String? password, MQTTVersion version, List subscribedTopics, List isTopicEnabledList, bool useTLS, bool useWebSocket, int qos, List messageHistory, String message, String publishTopic)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _MQTTRequestModel() when $default != null: +return $default(_that.brokerUrl,_that.port,_that.clientId,_that.username,_that.password,_that.version,_that.subscribedTopics,_that.isTopicEnabledList,_that.useTLS,_that.useWebSocket,_that.qos,_that.messageHistory,_that.message,_that.publishTopic);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String brokerUrl, int port, String? clientId, String? username, String? password, MQTTVersion version, List subscribedTopics, List isTopicEnabledList, bool useTLS, bool useWebSocket, int qos, List messageHistory, String message, String publishTopic) $default,) {final _that = this; +switch (_that) { +case _MQTTRequestModel(): +return $default(_that.brokerUrl,_that.port,_that.clientId,_that.username,_that.password,_that.version,_that.subscribedTopics,_that.isTopicEnabledList,_that.useTLS,_that.useWebSocket,_that.qos,_that.messageHistory,_that.message,_that.publishTopic);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String brokerUrl, int port, String? clientId, String? username, String? password, MQTTVersion version, List subscribedTopics, List isTopicEnabledList, bool useTLS, bool useWebSocket, int qos, List messageHistory, String message, String publishTopic)? $default,) {final _that = this; +switch (_that) { +case _MQTTRequestModel() when $default != null: +return $default(_that.brokerUrl,_that.port,_that.clientId,_that.username,_that.password,_that.version,_that.subscribedTopics,_that.isTopicEnabledList,_that.useTLS,_that.useWebSocket,_that.qos,_that.messageHistory,_that.message,_that.publishTopic);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _MQTTRequestModel implements MQTTRequestModel { + const _MQTTRequestModel({required this.brokerUrl, this.port = 1883, this.clientId, this.username, this.password, this.version = MQTTVersion.v5, final List subscribedTopics = const [], final List isTopicEnabledList = const [], this.useTLS = false, this.useWebSocket = false, this.qos = 0, final List messageHistory = const [], this.message = "", this.publishTopic = ""}): _subscribedTopics = subscribedTopics,_isTopicEnabledList = isTopicEnabledList,_messageHistory = messageHistory; + factory _MQTTRequestModel.fromJson(Map json) => _$MQTTRequestModelFromJson(json); + +@override final String brokerUrl; +@override@JsonKey() final int port; +@override final String? clientId; +@override final String? username; +@override final String? password; +@override@JsonKey() final MQTTVersion version; + final List _subscribedTopics; +@override@JsonKey() List get subscribedTopics { + if (_subscribedTopics is EqualUnmodifiableListView) return _subscribedTopics; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_subscribedTopics); +} + + final List _isTopicEnabledList; +@override@JsonKey() List get isTopicEnabledList { + if (_isTopicEnabledList is EqualUnmodifiableListView) return _isTopicEnabledList; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_isTopicEnabledList); +} + +@override@JsonKey() final bool useTLS; +@override@JsonKey() final bool useWebSocket; +@override@JsonKey() final int qos; + final List _messageHistory; +@override@JsonKey() List get messageHistory { + if (_messageHistory is EqualUnmodifiableListView) return _messageHistory; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_messageHistory); +} + +@override@JsonKey() final String message; +@override@JsonKey() final String publishTopic; + +/// Create a copy of MQTTRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$MQTTRequestModelCopyWith<_MQTTRequestModel> get copyWith => __$MQTTRequestModelCopyWithImpl<_MQTTRequestModel>(this, _$identity); + +@override +Map toJson() { + return _$MQTTRequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _MQTTRequestModel&&(identical(other.brokerUrl, brokerUrl) || other.brokerUrl == brokerUrl)&&(identical(other.port, port) || other.port == port)&&(identical(other.clientId, clientId) || other.clientId == clientId)&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.version, version) || other.version == version)&&const DeepCollectionEquality().equals(other._subscribedTopics, _subscribedTopics)&&const DeepCollectionEquality().equals(other._isTopicEnabledList, _isTopicEnabledList)&&(identical(other.useTLS, useTLS) || other.useTLS == useTLS)&&(identical(other.useWebSocket, useWebSocket) || other.useWebSocket == useWebSocket)&&(identical(other.qos, qos) || other.qos == qos)&&const DeepCollectionEquality().equals(other._messageHistory, _messageHistory)&&(identical(other.message, message) || other.message == message)&&(identical(other.publishTopic, publishTopic) || other.publishTopic == publishTopic)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,brokerUrl,port,clientId,username,password,version,const DeepCollectionEquality().hash(_subscribedTopics),const DeepCollectionEquality().hash(_isTopicEnabledList),useTLS,useWebSocket,qos,const DeepCollectionEquality().hash(_messageHistory),message,publishTopic); + +@override +String toString() { + return 'MQTTRequestModel(brokerUrl: $brokerUrl, port: $port, clientId: $clientId, username: $username, password: $password, version: $version, subscribedTopics: $subscribedTopics, isTopicEnabledList: $isTopicEnabledList, useTLS: $useTLS, useWebSocket: $useWebSocket, qos: $qos, messageHistory: $messageHistory, message: $message, publishTopic: $publishTopic)'; +} + + +} + +/// @nodoc +abstract mixin class _$MQTTRequestModelCopyWith<$Res> implements $MQTTRequestModelCopyWith<$Res> { + factory _$MQTTRequestModelCopyWith(_MQTTRequestModel value, $Res Function(_MQTTRequestModel) _then) = __$MQTTRequestModelCopyWithImpl; +@override @useResult +$Res call({ + String brokerUrl, int port, String? clientId, String? username, String? password, MQTTVersion version, List subscribedTopics, List isTopicEnabledList, bool useTLS, bool useWebSocket, int qos, List messageHistory, String message, String publishTopic +}); + + + + +} +/// @nodoc +class __$MQTTRequestModelCopyWithImpl<$Res> + implements _$MQTTRequestModelCopyWith<$Res> { + __$MQTTRequestModelCopyWithImpl(this._self, this._then); + + final _MQTTRequestModel _self; + final $Res Function(_MQTTRequestModel) _then; + +/// Create a copy of MQTTRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? brokerUrl = null,Object? port = null,Object? clientId = freezed,Object? username = freezed,Object? password = freezed,Object? version = null,Object? subscribedTopics = null,Object? isTopicEnabledList = null,Object? useTLS = null,Object? useWebSocket = null,Object? qos = null,Object? messageHistory = null,Object? message = null,Object? publishTopic = null,}) { + return _then(_MQTTRequestModel( +brokerUrl: null == brokerUrl ? _self.brokerUrl : brokerUrl // ignore: cast_nullable_to_non_nullable +as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable +as int,clientId: freezed == clientId ? _self.clientId : clientId // ignore: cast_nullable_to_non_nullable +as String?,username: freezed == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String?,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,version: null == version ? _self.version : version // ignore: cast_nullable_to_non_nullable +as MQTTVersion,subscribedTopics: null == subscribedTopics ? _self._subscribedTopics : subscribedTopics // ignore: cast_nullable_to_non_nullable +as List,isTopicEnabledList: null == isTopicEnabledList ? _self._isTopicEnabledList : isTopicEnabledList // ignore: cast_nullable_to_non_nullable +as List,useTLS: null == useTLS ? _self.useTLS : useTLS // ignore: cast_nullable_to_non_nullable +as bool,useWebSocket: null == useWebSocket ? _self.useWebSocket : useWebSocket // ignore: cast_nullable_to_non_nullable +as bool,qos: null == qos ? _self.qos : qos // ignore: cast_nullable_to_non_nullable +as int,messageHistory: null == messageHistory ? _self._messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,message: null == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String,publishTopic: null == publishTopic ? _self.publishTopic : publishTopic // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +// dart format on diff --git a/lib/models/protocols/mqtt_model.g.dart b/lib/models/protocols/mqtt_model.g.dart new file mode 100644 index 0000000000..6dec2bebba --- /dev/null +++ b/lib/models/protocols/mqtt_model.g.dart @@ -0,0 +1,63 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'mqtt_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_MQTTRequestModel _$MQTTRequestModelFromJson(Map json) => + _MQTTRequestModel( + brokerUrl: json['brokerUrl'] as String, + port: (json['port'] as num?)?.toInt() ?? 1883, + clientId: json['clientId'] as String?, + username: json['username'] as String?, + password: json['password'] as String?, + version: + $enumDecodeNullable(_$MQTTVersionEnumMap, json['version']) ?? + MQTTVersion.v5, + subscribedTopics: + (json['subscribedTopics'] as List?) + ?.map((e) => NameValueModel.fromJson(e as Map)) + .toList() ?? + const [], + isTopicEnabledList: + (json['isTopicEnabledList'] as List?) + ?.map((e) => e as bool) + .toList() ?? + const [], + useTLS: json['useTLS'] as bool? ?? false, + useWebSocket: json['useWebSocket'] as bool? ?? false, + qos: (json['qos'] as num?)?.toInt() ?? 0, + messageHistory: + (json['messageHistory'] as List?) + ?.map((e) => WebSocketMessage.fromJson(e as Map)) + .toList() ?? + const [], + message: json['message'] as String? ?? "", + publishTopic: json['publishTopic'] as String? ?? "", + ); + +Map _$MQTTRequestModelToJson(_MQTTRequestModel instance) => + { + 'brokerUrl': instance.brokerUrl, + 'port': instance.port, + 'clientId': instance.clientId, + 'username': instance.username, + 'password': instance.password, + 'version': _$MQTTVersionEnumMap[instance.version]!, + 'subscribedTopics': instance.subscribedTopics, + 'isTopicEnabledList': instance.isTopicEnabledList, + 'useTLS': instance.useTLS, + 'useWebSocket': instance.useWebSocket, + 'qos': instance.qos, + 'messageHistory': instance.messageHistory, + 'message': instance.message, + 'publishTopic': instance.publishTopic, + }; + +const _$MQTTVersionEnumMap = { + MQTTVersion.v3: 'v3', + MQTTVersion.v3_1_1: 'v3_1_1', + MQTTVersion.v5: 'v5', +}; diff --git a/lib/models/protocols/websocket_model.dart b/lib/models/protocols/websocket_model.dart new file mode 100644 index 0000000000..7510660977 --- /dev/null +++ b/lib/models/protocols/websocket_model.dart @@ -0,0 +1,37 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/models/protocols/base_protocol_model.dart'; + +part 'websocket_model.freezed.dart'; +part 'websocket_model.g.dart'; + +enum WebSocketMessageType { connected, sent, received, error } + +@freezed +abstract class WebSocketRequestModel + with _$WebSocketRequestModel + implements ProtocolModel { + const factory WebSocketRequestModel({ + required String url, + @Default([]) List messageHistory, + @Default({}) Map customHeaders, + @Default(false) bool autoReconnect, + }) = _WebSocketRequestModel; + + factory WebSocketRequestModel.fromJson(Map json) => + _$WebSocketRequestModelFromJson(json); +} + +/// Simple message model for WebSocket communication. +@freezed +abstract class WebSocketMessage with _$WebSocketMessage { + const factory WebSocketMessage({ + required String payload, + DateTime? timestamp, + @Default(true) bool outgoing, + @Default(WebSocketMessageType.received) WebSocketMessageType messageType, + int? qos, + }) = _WebSocketMessage; + + factory WebSocketMessage.fromJson(Map json) => + _$WebSocketMessageFromJson(json); +} diff --git a/lib/models/protocols/websocket_model.freezed.dart b/lib/models/protocols/websocket_model.freezed.dart new file mode 100644 index 0000000000..adbf9f2f9b --- /dev/null +++ b/lib/models/protocols/websocket_model.freezed.dart @@ -0,0 +1,573 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'websocket_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$WebSocketRequestModel { + + String get url; List get messageHistory; Map get customHeaders; bool get autoReconnect; +/// Create a copy of WebSocketRequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$WebSocketRequestModelCopyWith get copyWith => _$WebSocketRequestModelCopyWithImpl(this as WebSocketRequestModel, _$identity); + + /// Serializes this WebSocketRequestModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is WebSocketRequestModel&&(identical(other.url, url) || other.url == url)&&const DeepCollectionEquality().equals(other.messageHistory, messageHistory)&&const DeepCollectionEquality().equals(other.customHeaders, customHeaders)&&(identical(other.autoReconnect, autoReconnect) || other.autoReconnect == autoReconnect)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,url,const DeepCollectionEquality().hash(messageHistory),const DeepCollectionEquality().hash(customHeaders),autoReconnect); + +@override +String toString() { + return 'WebSocketRequestModel(url: $url, messageHistory: $messageHistory, customHeaders: $customHeaders, autoReconnect: $autoReconnect)'; +} + + +} + +/// @nodoc +abstract mixin class $WebSocketRequestModelCopyWith<$Res> { + factory $WebSocketRequestModelCopyWith(WebSocketRequestModel value, $Res Function(WebSocketRequestModel) _then) = _$WebSocketRequestModelCopyWithImpl; +@useResult +$Res call({ + String url, List messageHistory, Map customHeaders, bool autoReconnect +}); + + + + +} +/// @nodoc +class _$WebSocketRequestModelCopyWithImpl<$Res> + implements $WebSocketRequestModelCopyWith<$Res> { + _$WebSocketRequestModelCopyWithImpl(this._self, this._then); + + final WebSocketRequestModel _self; + final $Res Function(WebSocketRequestModel) _then; + +/// Create a copy of WebSocketRequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? url = null,Object? messageHistory = null,Object? customHeaders = null,Object? autoReconnect = null,}) { + return _then(_self.copyWith( +url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable +as String,messageHistory: null == messageHistory ? _self.messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,customHeaders: null == customHeaders ? _self.customHeaders : customHeaders // ignore: cast_nullable_to_non_nullable +as Map,autoReconnect: null == autoReconnect ? _self.autoReconnect : autoReconnect // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + +} + + +/// Adds pattern-matching-related methods to [WebSocketRequestModel]. +extension WebSocketRequestModelPatterns on WebSocketRequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _WebSocketRequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _WebSocketRequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _WebSocketRequestModel value) $default,){ +final _that = this; +switch (_that) { +case _WebSocketRequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _WebSocketRequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _WebSocketRequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String url, List messageHistory, Map customHeaders, bool autoReconnect)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _WebSocketRequestModel() when $default != null: +return $default(_that.url,_that.messageHistory,_that.customHeaders,_that.autoReconnect);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String url, List messageHistory, Map customHeaders, bool autoReconnect) $default,) {final _that = this; +switch (_that) { +case _WebSocketRequestModel(): +return $default(_that.url,_that.messageHistory,_that.customHeaders,_that.autoReconnect);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String url, List messageHistory, Map customHeaders, bool autoReconnect)? $default,) {final _that = this; +switch (_that) { +case _WebSocketRequestModel() when $default != null: +return $default(_that.url,_that.messageHistory,_that.customHeaders,_that.autoReconnect);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _WebSocketRequestModel implements WebSocketRequestModel { + const _WebSocketRequestModel({required this.url, final List messageHistory = const [], final Map customHeaders = const {}, this.autoReconnect = false}): _messageHistory = messageHistory,_customHeaders = customHeaders; + factory _WebSocketRequestModel.fromJson(Map json) => _$WebSocketRequestModelFromJson(json); + +@override final String url; + final List _messageHistory; +@override@JsonKey() List get messageHistory { + if (_messageHistory is EqualUnmodifiableListView) return _messageHistory; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_messageHistory); +} + + final Map _customHeaders; +@override@JsonKey() Map get customHeaders { + if (_customHeaders is EqualUnmodifiableMapView) return _customHeaders; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_customHeaders); +} + +@override@JsonKey() final bool autoReconnect; + +/// Create a copy of WebSocketRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$WebSocketRequestModelCopyWith<_WebSocketRequestModel> get copyWith => __$WebSocketRequestModelCopyWithImpl<_WebSocketRequestModel>(this, _$identity); + +@override +Map toJson() { + return _$WebSocketRequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WebSocketRequestModel&&(identical(other.url, url) || other.url == url)&&const DeepCollectionEquality().equals(other._messageHistory, _messageHistory)&&const DeepCollectionEquality().equals(other._customHeaders, _customHeaders)&&(identical(other.autoReconnect, autoReconnect) || other.autoReconnect == autoReconnect)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,url,const DeepCollectionEquality().hash(_messageHistory),const DeepCollectionEquality().hash(_customHeaders),autoReconnect); + +@override +String toString() { + return 'WebSocketRequestModel(url: $url, messageHistory: $messageHistory, customHeaders: $customHeaders, autoReconnect: $autoReconnect)'; +} + + +} + +/// @nodoc +abstract mixin class _$WebSocketRequestModelCopyWith<$Res> implements $WebSocketRequestModelCopyWith<$Res> { + factory _$WebSocketRequestModelCopyWith(_WebSocketRequestModel value, $Res Function(_WebSocketRequestModel) _then) = __$WebSocketRequestModelCopyWithImpl; +@override @useResult +$Res call({ + String url, List messageHistory, Map customHeaders, bool autoReconnect +}); + + + + +} +/// @nodoc +class __$WebSocketRequestModelCopyWithImpl<$Res> + implements _$WebSocketRequestModelCopyWith<$Res> { + __$WebSocketRequestModelCopyWithImpl(this._self, this._then); + + final _WebSocketRequestModel _self; + final $Res Function(_WebSocketRequestModel) _then; + +/// Create a copy of WebSocketRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? url = null,Object? messageHistory = null,Object? customHeaders = null,Object? autoReconnect = null,}) { + return _then(_WebSocketRequestModel( +url: null == url ? _self.url : url // ignore: cast_nullable_to_non_nullable +as String,messageHistory: null == messageHistory ? _self._messageHistory : messageHistory // ignore: cast_nullable_to_non_nullable +as List,customHeaders: null == customHeaders ? _self._customHeaders : customHeaders // ignore: cast_nullable_to_non_nullable +as Map,autoReconnect: null == autoReconnect ? _self.autoReconnect : autoReconnect // ignore: cast_nullable_to_non_nullable +as bool, + )); +} + + +} + + +/// @nodoc +mixin _$WebSocketMessage { + + String get payload; DateTime? get timestamp; bool get outgoing; WebSocketMessageType get messageType; int? get qos; +/// Create a copy of WebSocketMessage +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$WebSocketMessageCopyWith get copyWith => _$WebSocketMessageCopyWithImpl(this as WebSocketMessage, _$identity); + + /// Serializes this WebSocketMessage to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is WebSocketMessage&&(identical(other.payload, payload) || other.payload == payload)&&(identical(other.timestamp, timestamp) || other.timestamp == timestamp)&&(identical(other.outgoing, outgoing) || other.outgoing == outgoing)&&(identical(other.messageType, messageType) || other.messageType == messageType)&&(identical(other.qos, qos) || other.qos == qos)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,payload,timestamp,outgoing,messageType,qos); + +@override +String toString() { + return 'WebSocketMessage(payload: $payload, timestamp: $timestamp, outgoing: $outgoing, messageType: $messageType, qos: $qos)'; +} + + +} + +/// @nodoc +abstract mixin class $WebSocketMessageCopyWith<$Res> { + factory $WebSocketMessageCopyWith(WebSocketMessage value, $Res Function(WebSocketMessage) _then) = _$WebSocketMessageCopyWithImpl; +@useResult +$Res call({ + String payload, DateTime? timestamp, bool outgoing, WebSocketMessageType messageType, int? qos +}); + + + + +} +/// @nodoc +class _$WebSocketMessageCopyWithImpl<$Res> + implements $WebSocketMessageCopyWith<$Res> { + _$WebSocketMessageCopyWithImpl(this._self, this._then); + + final WebSocketMessage _self; + final $Res Function(WebSocketMessage) _then; + +/// Create a copy of WebSocketMessage +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? payload = null,Object? timestamp = freezed,Object? outgoing = null,Object? messageType = null,Object? qos = freezed,}) { + return _then(_self.copyWith( +payload: null == payload ? _self.payload : payload // ignore: cast_nullable_to_non_nullable +as String,timestamp: freezed == timestamp ? _self.timestamp : timestamp // ignore: cast_nullable_to_non_nullable +as DateTime?,outgoing: null == outgoing ? _self.outgoing : outgoing // ignore: cast_nullable_to_non_nullable +as bool,messageType: null == messageType ? _self.messageType : messageType // ignore: cast_nullable_to_non_nullable +as WebSocketMessageType,qos: freezed == qos ? _self.qos : qos // ignore: cast_nullable_to_non_nullable +as int?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [WebSocketMessage]. +extension WebSocketMessagePatterns on WebSocketMessage { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _WebSocketMessage value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _WebSocketMessage() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _WebSocketMessage value) $default,){ +final _that = this; +switch (_that) { +case _WebSocketMessage(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _WebSocketMessage value)? $default,){ +final _that = this; +switch (_that) { +case _WebSocketMessage() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String payload, DateTime? timestamp, bool outgoing, WebSocketMessageType messageType, int? qos)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _WebSocketMessage() when $default != null: +return $default(_that.payload,_that.timestamp,_that.outgoing,_that.messageType,_that.qos);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String payload, DateTime? timestamp, bool outgoing, WebSocketMessageType messageType, int? qos) $default,) {final _that = this; +switch (_that) { +case _WebSocketMessage(): +return $default(_that.payload,_that.timestamp,_that.outgoing,_that.messageType,_that.qos);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String payload, DateTime? timestamp, bool outgoing, WebSocketMessageType messageType, int? qos)? $default,) {final _that = this; +switch (_that) { +case _WebSocketMessage() when $default != null: +return $default(_that.payload,_that.timestamp,_that.outgoing,_that.messageType,_that.qos);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _WebSocketMessage implements WebSocketMessage { + const _WebSocketMessage({required this.payload, this.timestamp, this.outgoing = true, this.messageType = WebSocketMessageType.received, this.qos}); + factory _WebSocketMessage.fromJson(Map json) => _$WebSocketMessageFromJson(json); + +@override final String payload; +@override final DateTime? timestamp; +@override@JsonKey() final bool outgoing; +@override@JsonKey() final WebSocketMessageType messageType; +@override final int? qos; + +/// Create a copy of WebSocketMessage +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$WebSocketMessageCopyWith<_WebSocketMessage> get copyWith => __$WebSocketMessageCopyWithImpl<_WebSocketMessage>(this, _$identity); + +@override +Map toJson() { + return _$WebSocketMessageToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WebSocketMessage&&(identical(other.payload, payload) || other.payload == payload)&&(identical(other.timestamp, timestamp) || other.timestamp == timestamp)&&(identical(other.outgoing, outgoing) || other.outgoing == outgoing)&&(identical(other.messageType, messageType) || other.messageType == messageType)&&(identical(other.qos, qos) || other.qos == qos)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,payload,timestamp,outgoing,messageType,qos); + +@override +String toString() { + return 'WebSocketMessage(payload: $payload, timestamp: $timestamp, outgoing: $outgoing, messageType: $messageType, qos: $qos)'; +} + + +} + +/// @nodoc +abstract mixin class _$WebSocketMessageCopyWith<$Res> implements $WebSocketMessageCopyWith<$Res> { + factory _$WebSocketMessageCopyWith(_WebSocketMessage value, $Res Function(_WebSocketMessage) _then) = __$WebSocketMessageCopyWithImpl; +@override @useResult +$Res call({ + String payload, DateTime? timestamp, bool outgoing, WebSocketMessageType messageType, int? qos +}); + + + + +} +/// @nodoc +class __$WebSocketMessageCopyWithImpl<$Res> + implements _$WebSocketMessageCopyWith<$Res> { + __$WebSocketMessageCopyWithImpl(this._self, this._then); + + final _WebSocketMessage _self; + final $Res Function(_WebSocketMessage) _then; + +/// Create a copy of WebSocketMessage +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? payload = null,Object? timestamp = freezed,Object? outgoing = null,Object? messageType = null,Object? qos = freezed,}) { + return _then(_WebSocketMessage( +payload: null == payload ? _self.payload : payload // ignore: cast_nullable_to_non_nullable +as String,timestamp: freezed == timestamp ? _self.timestamp : timestamp // ignore: cast_nullable_to_non_nullable +as DateTime?,outgoing: null == outgoing ? _self.outgoing : outgoing // ignore: cast_nullable_to_non_nullable +as bool,messageType: null == messageType ? _self.messageType : messageType // ignore: cast_nullable_to_non_nullable +as WebSocketMessageType,qos: freezed == qos ? _self.qos : qos // ignore: cast_nullable_to_non_nullable +as int?, + )); +} + + +} + +// dart format on diff --git a/lib/models/protocols/websocket_model.g.dart b/lib/models/protocols/websocket_model.g.dart new file mode 100644 index 0000000000..7b78fe9518 --- /dev/null +++ b/lib/models/protocols/websocket_model.g.dart @@ -0,0 +1,65 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'websocket_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_WebSocketRequestModel _$WebSocketRequestModelFromJson( + Map json, +) => _WebSocketRequestModel( + url: json['url'] as String, + messageHistory: + (json['messageHistory'] as List?) + ?.map((e) => WebSocketMessage.fromJson(e as Map)) + .toList() ?? + const [], + customHeaders: + (json['customHeaders'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ) ?? + const {}, + autoReconnect: json['autoReconnect'] as bool? ?? false, +); + +Map _$WebSocketRequestModelToJson( + _WebSocketRequestModel instance, +) => { + 'url': instance.url, + 'messageHistory': instance.messageHistory, + 'customHeaders': instance.customHeaders, + 'autoReconnect': instance.autoReconnect, +}; + +_WebSocketMessage _$WebSocketMessageFromJson(Map json) => + _WebSocketMessage( + payload: json['payload'] as String, + timestamp: json['timestamp'] == null + ? null + : DateTime.parse(json['timestamp'] as String), + outgoing: json['outgoing'] as bool? ?? true, + messageType: + $enumDecodeNullable( + _$WebSocketMessageTypeEnumMap, + json['messageType'], + ) ?? + WebSocketMessageType.received, + qos: (json['qos'] as num?)?.toInt(), + ); + +Map _$WebSocketMessageToJson(_WebSocketMessage instance) => + { + 'payload': instance.payload, + 'timestamp': instance.timestamp?.toIso8601String(), + 'outgoing': instance.outgoing, + 'messageType': _$WebSocketMessageTypeEnumMap[instance.messageType]!, + 'qos': instance.qos, + }; + +const _$WebSocketMessageTypeEnumMap = { + WebSocketMessageType.connected: 'connected', + WebSocketMessageType.sent: 'sent', + WebSocketMessageType.received: 'received', + WebSocketMessageType.error: 'error', +}; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 25c3608435..5c43c2a94d 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,11 +1,12 @@ import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/models/protocols/base_protocol_model.dart'; part 'request_model.freezed.dart'; part 'request_model.g.dart'; @freezed -class RequestModel with _$RequestModel { +abstract class RequestModel with _$RequestModel { @JsonSerializable( explicitToJson: true, anyMap: true, @@ -26,6 +27,7 @@ class RequestModel with _$RequestModel { String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel, + @ProtocolModelConverter() ProtocolModel? protocolModel, }) = _RequestModel; factory RequestModel.fromJson(Map json) => diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index d700dba947..869ec1969e 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -1,5 +1,5 @@ -// coverage:ignore-file // GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark @@ -9,536 +9,386 @@ part of 'request_model.dart'; // FreezedGenerator // ************************************************************************** +// dart format off T _$identity(T value) => value; -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -RequestModel _$RequestModelFromJson(Map json) { - return _RequestModel.fromJson(json); -} - /// @nodoc mixin _$RequestModel { - String get id => throw _privateConstructorUsedError; - APIType get apiType => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - String get description => throw _privateConstructorUsedError; - @JsonKey(includeToJson: false) - dynamic get requestTabIndex => throw _privateConstructorUsedError; - HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; - int? get responseStatus => throw _privateConstructorUsedError; - String? get message => throw _privateConstructorUsedError; - HttpResponseModel? get httpResponseModel => - throw _privateConstructorUsedError; - @JsonKey(includeToJson: false) - bool get isWorking => throw _privateConstructorUsedError; - @JsonKey(includeToJson: false) - DateTime? get sendingTime => throw _privateConstructorUsedError; - @JsonKey(includeToJson: false) - bool get isStreaming => throw _privateConstructorUsedError; - String? get preRequestScript => throw _privateConstructorUsedError; - String? get postRequestScript => throw _privateConstructorUsedError; - AIRequestModel? get aiRequestModel => throw _privateConstructorUsedError; + + String get id; APIType get apiType; String get name; String get description;@JsonKey(includeToJson: false) dynamic get requestTabIndex; HttpRequestModel? get httpRequestModel; int? get responseStatus; String? get message; HttpResponseModel? get httpResponseModel;@JsonKey(includeToJson: false) bool get isWorking;@JsonKey(includeToJson: false) DateTime? get sendingTime;@JsonKey(includeToJson: false) bool get isStreaming; String? get preRequestScript; String? get postRequestScript; AIRequestModel? get aiRequestModel;@ProtocolModelConverter() ProtocolModel? get protocolModel; +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RequestModelCopyWith get copyWith => _$RequestModelCopyWithImpl(this as RequestModel, _$identity); /// Serializes this RequestModel to a JSON map. - Map toJson() => throw _privateConstructorUsedError; + Map toJson(); - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - $RequestModelCopyWith get copyWith => - throw _privateConstructorUsedError; + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.apiType, apiType) || other.apiType == apiType)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.requestTabIndex, requestTabIndex)&&(identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel)&&(identical(other.responseStatus, responseStatus) || other.responseStatus == responseStatus)&&(identical(other.message, message) || other.message == message)&&(identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel)&&(identical(other.isWorking, isWorking) || other.isWorking == isWorking)&&(identical(other.sendingTime, sendingTime) || other.sendingTime == sendingTime)&&(identical(other.isStreaming, isStreaming) || other.isStreaming == isStreaming)&&(identical(other.preRequestScript, preRequestScript) || other.preRequestScript == preRequestScript)&&(identical(other.postRequestScript, postRequestScript) || other.postRequestScript == postRequestScript)&&(identical(other.aiRequestModel, aiRequestModel) || other.aiRequestModel == aiRequestModel)&&(identical(other.protocolModel, protocolModel) || other.protocolModel == protocolModel)); } -/// @nodoc -abstract class $RequestModelCopyWith<$Res> { - factory $RequestModelCopyWith( - RequestModel value, $Res Function(RequestModel) then) = - _$RequestModelCopyWithImpl<$Res, RequestModel>; - @useResult - $Res call( - {String id, - APIType apiType, - String name, - String description, - @JsonKey(includeToJson: false) dynamic requestTabIndex, - HttpRequestModel? httpRequestModel, - int? responseStatus, - String? message, - HttpResponseModel? httpResponseModel, - @JsonKey(includeToJson: false) bool isWorking, - @JsonKey(includeToJson: false) DateTime? sendingTime, - @JsonKey(includeToJson: false) bool isStreaming, - String? preRequestScript, - String? postRequestScript, - AIRequestModel? aiRequestModel}); - - $HttpRequestModelCopyWith<$Res>? get httpRequestModel; - $HttpResponseModelCopyWith<$Res>? get httpResponseModel; - $AIRequestModelCopyWith<$Res>? get aiRequestModel; +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,apiType,name,description,const DeepCollectionEquality().hash(requestTabIndex),httpRequestModel,responseStatus,message,httpResponseModel,isWorking,sendingTime,isStreaming,preRequestScript,postRequestScript,aiRequestModel,protocolModel); + +@override +String toString() { + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, isStreaming: $isStreaming, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, aiRequestModel: $aiRequestModel, protocolModel: $protocolModel)'; +} + + } /// @nodoc -class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> +abstract mixin class $RequestModelCopyWith<$Res> { + factory $RequestModelCopyWith(RequestModel value, $Res Function(RequestModel) _then) = _$RequestModelCopyWithImpl; +@useResult +$Res call({ + String id, APIType apiType, String name, String description,@JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel,@JsonKey(includeToJson: false) bool isWorking,@JsonKey(includeToJson: false) DateTime? sendingTime,@JsonKey(includeToJson: false) bool isStreaming, String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel,@ProtocolModelConverter() ProtocolModel? protocolModel +}); + + +$HttpRequestModelCopyWith<$Res>? get httpRequestModel;$HttpResponseModelCopyWith<$Res>? get httpResponseModel;$AIRequestModelCopyWith<$Res>? get aiRequestModel; + +} +/// @nodoc +class _$RequestModelCopyWithImpl<$Res> implements $RequestModelCopyWith<$Res> { - _$RequestModelCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? apiType = null, - Object? name = null, - Object? description = null, - Object? requestTabIndex = freezed, - Object? httpRequestModel = freezed, - Object? responseStatus = freezed, - Object? message = freezed, - Object? httpResponseModel = freezed, - Object? isWorking = null, - Object? sendingTime = freezed, - Object? isStreaming = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, - Object? aiRequestModel = freezed, - }) { - return _then(_value.copyWith( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - apiType: null == apiType - ? _value.apiType - : apiType // ignore: cast_nullable_to_non_nullable - as APIType, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - requestTabIndex: freezed == requestTabIndex - ? _value.requestTabIndex - : requestTabIndex // ignore: cast_nullable_to_non_nullable - as dynamic, - httpRequestModel: freezed == httpRequestModel - ? _value.httpRequestModel - : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel?, - responseStatus: freezed == responseStatus - ? _value.responseStatus - : responseStatus // ignore: cast_nullable_to_non_nullable - as int?, - message: freezed == message - ? _value.message - : message // ignore: cast_nullable_to_non_nullable - as String?, - httpResponseModel: freezed == httpResponseModel - ? _value.httpResponseModel - : httpResponseModel // ignore: cast_nullable_to_non_nullable - as HttpResponseModel?, - isWorking: null == isWorking - ? _value.isWorking - : isWorking // ignore: cast_nullable_to_non_nullable - as bool, - sendingTime: freezed == sendingTime - ? _value.sendingTime - : sendingTime // ignore: cast_nullable_to_non_nullable - as DateTime?, - isStreaming: null == isStreaming - ? _value.isStreaming - : isStreaming // ignore: cast_nullable_to_non_nullable - as bool, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - aiRequestModel: freezed == aiRequestModel - ? _value.aiRequestModel - : aiRequestModel // ignore: cast_nullable_to_non_nullable - as AIRequestModel?, - ) as $Val); + _$RequestModelCopyWithImpl(this._self, this._then); + + final RequestModel _self; + final $Res Function(RequestModel) _then; + +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? apiType = null,Object? name = null,Object? description = null,Object? requestTabIndex = freezed,Object? httpRequestModel = freezed,Object? responseStatus = freezed,Object? message = freezed,Object? httpResponseModel = freezed,Object? isWorking = null,Object? sendingTime = freezed,Object? isStreaming = null,Object? preRequestScript = freezed,Object? postRequestScript = freezed,Object? aiRequestModel = freezed,Object? protocolModel = freezed,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,apiType: null == apiType ? _self.apiType : apiType // ignore: cast_nullable_to_non_nullable +as APIType,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String,requestTabIndex: freezed == requestTabIndex ? _self.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable +as dynamic,httpRequestModel: freezed == httpRequestModel ? _self.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable +as HttpRequestModel?,responseStatus: freezed == responseStatus ? _self.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable +as int?,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,httpResponseModel: freezed == httpResponseModel ? _self.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable +as HttpResponseModel?,isWorking: null == isWorking ? _self.isWorking : isWorking // ignore: cast_nullable_to_non_nullable +as bool,sendingTime: freezed == sendingTime ? _self.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable +as DateTime?,isStreaming: null == isStreaming ? _self.isStreaming : isStreaming // ignore: cast_nullable_to_non_nullable +as bool,preRequestScript: freezed == preRequestScript ? _self.preRequestScript : preRequestScript // ignore: cast_nullable_to_non_nullable +as String?,postRequestScript: freezed == postRequestScript ? _self.postRequestScript : postRequestScript // ignore: cast_nullable_to_non_nullable +as String?,aiRequestModel: freezed == aiRequestModel ? _self.aiRequestModel : aiRequestModel // ignore: cast_nullable_to_non_nullable +as AIRequestModel?,protocolModel: freezed == protocolModel ? _self.protocolModel : protocolModel // ignore: cast_nullable_to_non_nullable +as ProtocolModel?, + )); +} +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpRequestModelCopyWith<$Res>? get httpRequestModel { + if (_self.httpRequestModel == null) { + return null; } - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $HttpRequestModelCopyWith<$Res>? get httpRequestModel { - if (_value.httpRequestModel == null) { - return null; - } - - return $HttpRequestModelCopyWith<$Res>(_value.httpRequestModel!, (value) { - return _then(_value.copyWith(httpRequestModel: value) as $Val); - }); + return $HttpRequestModelCopyWith<$Res>(_self.httpRequestModel!, (value) { + return _then(_self.copyWith(httpRequestModel: value)); + }); +}/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpResponseModelCopyWith<$Res>? get httpResponseModel { + if (_self.httpResponseModel == null) { + return null; } - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $HttpResponseModelCopyWith<$Res>? get httpResponseModel { - if (_value.httpResponseModel == null) { - return null; - } - - return $HttpResponseModelCopyWith<$Res>(_value.httpResponseModel!, (value) { - return _then(_value.copyWith(httpResponseModel: value) as $Val); - }); + return $HttpResponseModelCopyWith<$Res>(_self.httpResponseModel!, (value) { + return _then(_self.copyWith(httpResponseModel: value)); + }); +}/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AIRequestModelCopyWith<$Res>? get aiRequestModel { + if (_self.aiRequestModel == null) { + return null; } - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AIRequestModelCopyWith<$Res>? get aiRequestModel { - if (_value.aiRequestModel == null) { - return null; - } - - return $AIRequestModelCopyWith<$Res>(_value.aiRequestModel!, (value) { - return _then(_value.copyWith(aiRequestModel: value) as $Val); - }); - } + return $AIRequestModelCopyWith<$Res>(_self.aiRequestModel!, (value) { + return _then(_self.copyWith(aiRequestModel: value)); + }); +} } -/// @nodoc -abstract class _$$RequestModelImplCopyWith<$Res> - implements $RequestModelCopyWith<$Res> { - factory _$$RequestModelImplCopyWith( - _$RequestModelImpl value, $Res Function(_$RequestModelImpl) then) = - __$$RequestModelImplCopyWithImpl<$Res>; - @override - @useResult - $Res call( - {String id, - APIType apiType, - String name, - String description, - @JsonKey(includeToJson: false) dynamic requestTabIndex, - HttpRequestModel? httpRequestModel, - int? responseStatus, - String? message, - HttpResponseModel? httpResponseModel, - @JsonKey(includeToJson: false) bool isWorking, - @JsonKey(includeToJson: false) DateTime? sendingTime, - @JsonKey(includeToJson: false) bool isStreaming, - String? preRequestScript, - String? postRequestScript, - AIRequestModel? aiRequestModel}); - - @override - $HttpRequestModelCopyWith<$Res>? get httpRequestModel; - @override - $HttpResponseModelCopyWith<$Res>? get httpResponseModel; - @override - $AIRequestModelCopyWith<$Res>? get aiRequestModel; + +/// Adds pattern-matching-related methods to [RequestModel]. +extension RequestModelPatterns on RequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RequestModel value) $default,){ +final _that = this; +switch (_that) { +case _RequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _RequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, APIType apiType, String name, String description, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, @JsonKey(includeToJson: false) bool isStreaming, String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel, @ProtocolModelConverter() ProtocolModel? protocolModel)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RequestModel() when $default != null: +return $default(_that.id,_that.apiType,_that.name,_that.description,_that.requestTabIndex,_that.httpRequestModel,_that.responseStatus,_that.message,_that.httpResponseModel,_that.isWorking,_that.sendingTime,_that.isStreaming,_that.preRequestScript,_that.postRequestScript,_that.aiRequestModel,_that.protocolModel);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String id, APIType apiType, String name, String description, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, @JsonKey(includeToJson: false) bool isStreaming, String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel, @ProtocolModelConverter() ProtocolModel? protocolModel) $default,) {final _that = this; +switch (_that) { +case _RequestModel(): +return $default(_that.id,_that.apiType,_that.name,_that.description,_that.requestTabIndex,_that.httpRequestModel,_that.responseStatus,_that.message,_that.httpResponseModel,_that.isWorking,_that.sendingTime,_that.isStreaming,_that.preRequestScript,_that.postRequestScript,_that.aiRequestModel,_that.protocolModel);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, APIType apiType, String name, String description, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, @JsonKey(includeToJson: false) bool isStreaming, String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel, @ProtocolModelConverter() ProtocolModel? protocolModel)? $default,) {final _that = this; +switch (_that) { +case _RequestModel() when $default != null: +return $default(_that.id,_that.apiType,_that.name,_that.description,_that.requestTabIndex,_that.httpRequestModel,_that.responseStatus,_that.message,_that.httpResponseModel,_that.isWorking,_that.sendingTime,_that.isStreaming,_that.preRequestScript,_that.postRequestScript,_that.aiRequestModel,_that.protocolModel);case _: + return null; + +} } -/// @nodoc -class __$$RequestModelImplCopyWithImpl<$Res> - extends _$RequestModelCopyWithImpl<$Res, _$RequestModelImpl> - implements _$$RequestModelImplCopyWith<$Res> { - __$$RequestModelImplCopyWithImpl( - _$RequestModelImpl _value, $Res Function(_$RequestModelImpl) _then) - : super(_value, _then); - - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? id = null, - Object? apiType = null, - Object? name = null, - Object? description = null, - Object? requestTabIndex = freezed, - Object? httpRequestModel = freezed, - Object? responseStatus = freezed, - Object? message = freezed, - Object? httpResponseModel = freezed, - Object? isWorking = null, - Object? sendingTime = freezed, - Object? isStreaming = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, - Object? aiRequestModel = freezed, - }) { - return _then(_$RequestModelImpl( - id: null == id - ? _value.id - : id // ignore: cast_nullable_to_non_nullable - as String, - apiType: null == apiType - ? _value.apiType - : apiType // ignore: cast_nullable_to_non_nullable - as APIType, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - description: null == description - ? _value.description - : description // ignore: cast_nullable_to_non_nullable - as String, - requestTabIndex: freezed == requestTabIndex - ? _value.requestTabIndex! - : requestTabIndex, - httpRequestModel: freezed == httpRequestModel - ? _value.httpRequestModel - : httpRequestModel // ignore: cast_nullable_to_non_nullable - as HttpRequestModel?, - responseStatus: freezed == responseStatus - ? _value.responseStatus - : responseStatus // ignore: cast_nullable_to_non_nullable - as int?, - message: freezed == message - ? _value.message - : message // ignore: cast_nullable_to_non_nullable - as String?, - httpResponseModel: freezed == httpResponseModel - ? _value.httpResponseModel - : httpResponseModel // ignore: cast_nullable_to_non_nullable - as HttpResponseModel?, - isWorking: null == isWorking - ? _value.isWorking - : isWorking // ignore: cast_nullable_to_non_nullable - as bool, - sendingTime: freezed == sendingTime - ? _value.sendingTime - : sendingTime // ignore: cast_nullable_to_non_nullable - as DateTime?, - isStreaming: null == isStreaming - ? _value.isStreaming - : isStreaming // ignore: cast_nullable_to_non_nullable - as bool, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - aiRequestModel: freezed == aiRequestModel - ? _value.aiRequestModel - : aiRequestModel // ignore: cast_nullable_to_non_nullable - as AIRequestModel?, - )); - } } /// @nodoc @JsonSerializable(explicitToJson: true, anyMap: true) -class _$RequestModelImpl implements _RequestModel { - const _$RequestModelImpl( - {required this.id, - this.apiType = APIType.rest, - this.name = "", - this.description = "", - @JsonKey(includeToJson: false) this.requestTabIndex = 0, - this.httpRequestModel, - this.responseStatus, - this.message, - this.httpResponseModel, - @JsonKey(includeToJson: false) this.isWorking = false, - @JsonKey(includeToJson: false) this.sendingTime, - @JsonKey(includeToJson: false) this.isStreaming = false, - this.preRequestScript, - this.postRequestScript, - this.aiRequestModel}); - - factory _$RequestModelImpl.fromJson(Map json) => - _$$RequestModelImplFromJson(json); - - @override - final String id; - @override - @JsonKey() - final APIType apiType; - @override - @JsonKey() - final String name; - @override - @JsonKey() - final String description; - @override - @JsonKey(includeToJson: false) - final dynamic requestTabIndex; - @override - final HttpRequestModel? httpRequestModel; - @override - final int? responseStatus; - @override - final String? message; - @override - final HttpResponseModel? httpResponseModel; - @override - @JsonKey(includeToJson: false) - final bool isWorking; - @override - @JsonKey(includeToJson: false) - final DateTime? sendingTime; - @override - @JsonKey(includeToJson: false) - final bool isStreaming; - @override - final String? preRequestScript; - @override - final String? postRequestScript; - @override - final AIRequestModel? aiRequestModel; - - @override - String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, isStreaming: $isStreaming, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, aiRequestModel: $aiRequestModel)'; +class _RequestModel implements RequestModel { + const _RequestModel({required this.id, this.apiType = APIType.rest, this.name = "", this.description = "", @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, this.responseStatus, this.message, this.httpResponseModel, @JsonKey(includeToJson: false) this.isWorking = false, @JsonKey(includeToJson: false) this.sendingTime, @JsonKey(includeToJson: false) this.isStreaming = false, this.preRequestScript, this.postRequestScript, this.aiRequestModel, @ProtocolModelConverter() this.protocolModel}); + factory _RequestModel.fromJson(Map json) => _$RequestModelFromJson(json); + +@override final String id; +@override@JsonKey() final APIType apiType; +@override@JsonKey() final String name; +@override@JsonKey() final String description; +@override@JsonKey(includeToJson: false) final dynamic requestTabIndex; +@override final HttpRequestModel? httpRequestModel; +@override final int? responseStatus; +@override final String? message; +@override final HttpResponseModel? httpResponseModel; +@override@JsonKey(includeToJson: false) final bool isWorking; +@override@JsonKey(includeToJson: false) final DateTime? sendingTime; +@override@JsonKey(includeToJson: false) final bool isStreaming; +@override final String? preRequestScript; +@override final String? postRequestScript; +@override final AIRequestModel? aiRequestModel; +@override@ProtocolModelConverter() final ProtocolModel? protocolModel; + +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RequestModelCopyWith<_RequestModel> get copyWith => __$RequestModelCopyWithImpl<_RequestModel>(this, _$identity); + +@override +Map toJson() { + return _$RequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.apiType, apiType) || other.apiType == apiType)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&const DeepCollectionEquality().equals(other.requestTabIndex, requestTabIndex)&&(identical(other.httpRequestModel, httpRequestModel) || other.httpRequestModel == httpRequestModel)&&(identical(other.responseStatus, responseStatus) || other.responseStatus == responseStatus)&&(identical(other.message, message) || other.message == message)&&(identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel)&&(identical(other.isWorking, isWorking) || other.isWorking == isWorking)&&(identical(other.sendingTime, sendingTime) || other.sendingTime == sendingTime)&&(identical(other.isStreaming, isStreaming) || other.isStreaming == isStreaming)&&(identical(other.preRequestScript, preRequestScript) || other.preRequestScript == preRequestScript)&&(identical(other.postRequestScript, postRequestScript) || other.postRequestScript == postRequestScript)&&(identical(other.aiRequestModel, aiRequestModel) || other.aiRequestModel == aiRequestModel)&&(identical(other.protocolModel, protocolModel) || other.protocolModel == protocolModel)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,apiType,name,description,const DeepCollectionEquality().hash(requestTabIndex),httpRequestModel,responseStatus,message,httpResponseModel,isWorking,sendingTime,isStreaming,preRequestScript,postRequestScript,aiRequestModel,protocolModel); + +@override +String toString() { + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, isStreaming: $isStreaming, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, aiRequestModel: $aiRequestModel, protocolModel: $protocolModel)'; +} + + +} + +/// @nodoc +abstract mixin class _$RequestModelCopyWith<$Res> implements $RequestModelCopyWith<$Res> { + factory _$RequestModelCopyWith(_RequestModel value, $Res Function(_RequestModel) _then) = __$RequestModelCopyWithImpl; +@override @useResult +$Res call({ + String id, APIType apiType, String name, String description,@JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, String? message, HttpResponseModel? httpResponseModel,@JsonKey(includeToJson: false) bool isWorking,@JsonKey(includeToJson: false) DateTime? sendingTime,@JsonKey(includeToJson: false) bool isStreaming, String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel,@ProtocolModelConverter() ProtocolModel? protocolModel +}); + + +@override $HttpRequestModelCopyWith<$Res>? get httpRequestModel;@override $HttpResponseModelCopyWith<$Res>? get httpResponseModel;@override $AIRequestModelCopyWith<$Res>? get aiRequestModel; + +} +/// @nodoc +class __$RequestModelCopyWithImpl<$Res> + implements _$RequestModelCopyWith<$Res> { + __$RequestModelCopyWithImpl(this._self, this._then); + + final _RequestModel _self; + final $Res Function(_RequestModel) _then; + +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? apiType = null,Object? name = null,Object? description = null,Object? requestTabIndex = freezed,Object? httpRequestModel = freezed,Object? responseStatus = freezed,Object? message = freezed,Object? httpResponseModel = freezed,Object? isWorking = null,Object? sendingTime = freezed,Object? isStreaming = null,Object? preRequestScript = freezed,Object? postRequestScript = freezed,Object? aiRequestModel = freezed,Object? protocolModel = freezed,}) { + return _then(_RequestModel( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as String,apiType: null == apiType ? _self.apiType : apiType // ignore: cast_nullable_to_non_nullable +as APIType,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String,requestTabIndex: freezed == requestTabIndex ? _self.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable +as dynamic,httpRequestModel: freezed == httpRequestModel ? _self.httpRequestModel : httpRequestModel // ignore: cast_nullable_to_non_nullable +as HttpRequestModel?,responseStatus: freezed == responseStatus ? _self.responseStatus : responseStatus // ignore: cast_nullable_to_non_nullable +as int?,message: freezed == message ? _self.message : message // ignore: cast_nullable_to_non_nullable +as String?,httpResponseModel: freezed == httpResponseModel ? _self.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable +as HttpResponseModel?,isWorking: null == isWorking ? _self.isWorking : isWorking // ignore: cast_nullable_to_non_nullable +as bool,sendingTime: freezed == sendingTime ? _self.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable +as DateTime?,isStreaming: null == isStreaming ? _self.isStreaming : isStreaming // ignore: cast_nullable_to_non_nullable +as bool,preRequestScript: freezed == preRequestScript ? _self.preRequestScript : preRequestScript // ignore: cast_nullable_to_non_nullable +as String?,postRequestScript: freezed == postRequestScript ? _self.postRequestScript : postRequestScript // ignore: cast_nullable_to_non_nullable +as String?,aiRequestModel: freezed == aiRequestModel ? _self.aiRequestModel : aiRequestModel // ignore: cast_nullable_to_non_nullable +as AIRequestModel?,protocolModel: freezed == protocolModel ? _self.protocolModel : protocolModel // ignore: cast_nullable_to_non_nullable +as ProtocolModel?, + )); +} + +/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpRequestModelCopyWith<$Res>? get httpRequestModel { + if (_self.httpRequestModel == null) { + return null; } - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$RequestModelImpl && - (identical(other.id, id) || other.id == id) && - (identical(other.apiType, apiType) || other.apiType == apiType) && - (identical(other.name, name) || other.name == name) && - (identical(other.description, description) || - other.description == description) && - const DeepCollectionEquality() - .equals(other.requestTabIndex, requestTabIndex) && - (identical(other.httpRequestModel, httpRequestModel) || - other.httpRequestModel == httpRequestModel) && - (identical(other.responseStatus, responseStatus) || - other.responseStatus == responseStatus) && - (identical(other.message, message) || other.message == message) && - (identical(other.httpResponseModel, httpResponseModel) || - other.httpResponseModel == httpResponseModel) && - (identical(other.isWorking, isWorking) || - other.isWorking == isWorking) && - (identical(other.sendingTime, sendingTime) || - other.sendingTime == sendingTime) && - (identical(other.isStreaming, isStreaming) || - other.isStreaming == isStreaming) && - (identical(other.preRequestScript, preRequestScript) || - other.preRequestScript == preRequestScript) && - (identical(other.postRequestScript, postRequestScript) || - other.postRequestScript == postRequestScript) && - (identical(other.aiRequestModel, aiRequestModel) || - other.aiRequestModel == aiRequestModel)); + return $HttpRequestModelCopyWith<$Res>(_self.httpRequestModel!, (value) { + return _then(_self.copyWith(httpRequestModel: value)); + }); +}/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HttpResponseModelCopyWith<$Res>? get httpResponseModel { + if (_self.httpResponseModel == null) { + return null; } - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash( - runtimeType, - id, - apiType, - name, - description, - const DeepCollectionEquality().hash(requestTabIndex), - httpRequestModel, - responseStatus, - message, - httpResponseModel, - isWorking, - sendingTime, - isStreaming, - preRequestScript, - postRequestScript, - aiRequestModel); - - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$RequestModelImplCopyWith<_$RequestModelImpl> get copyWith => - __$$RequestModelImplCopyWithImpl<_$RequestModelImpl>(this, _$identity); - - @override - Map toJson() { - return _$$RequestModelImplToJson( - this, - ); + return $HttpResponseModelCopyWith<$Res>(_self.httpResponseModel!, (value) { + return _then(_self.copyWith(httpResponseModel: value)); + }); +}/// Create a copy of RequestModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AIRequestModelCopyWith<$Res>? get aiRequestModel { + if (_self.aiRequestModel == null) { + return null; } -} -abstract class _RequestModel implements RequestModel { - const factory _RequestModel( - {required final String id, - final APIType apiType, - final String name, - final String description, - @JsonKey(includeToJson: false) final dynamic requestTabIndex, - final HttpRequestModel? httpRequestModel, - final int? responseStatus, - final String? message, - final HttpResponseModel? httpResponseModel, - @JsonKey(includeToJson: false) final bool isWorking, - @JsonKey(includeToJson: false) final DateTime? sendingTime, - @JsonKey(includeToJson: false) final bool isStreaming, - final String? preRequestScript, - final String? postRequestScript, - final AIRequestModel? aiRequestModel}) = _$RequestModelImpl; - - factory _RequestModel.fromJson(Map json) = - _$RequestModelImpl.fromJson; - - @override - String get id; - @override - APIType get apiType; - @override - String get name; - @override - String get description; - @override - @JsonKey(includeToJson: false) - dynamic get requestTabIndex; - @override - HttpRequestModel? get httpRequestModel; - @override - int? get responseStatus; - @override - String? get message; - @override - HttpResponseModel? get httpResponseModel; - @override - @JsonKey(includeToJson: false) - bool get isWorking; - @override - @JsonKey(includeToJson: false) - DateTime? get sendingTime; - @override - @JsonKey(includeToJson: false) - bool get isStreaming; - @override - String? get preRequestScript; - @override - String? get postRequestScript; - @override - AIRequestModel? get aiRequestModel; - - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @JsonKey(includeFromJson: false, includeToJson: false) - _$$RequestModelImplCopyWith<_$RequestModelImpl> get copyWith => - throw _privateConstructorUsedError; + return $AIRequestModelCopyWith<$Res>(_self.aiRequestModel!, (value) { + return _then(_self.copyWith(aiRequestModel: value)); + }); +} } + +// dart format on diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index 272bfca0c9..617e7242ac 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -6,37 +6,41 @@ part of 'request_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( - id: json['id'] as String, - apiType: $enumDecodeNullable(_$APITypeEnumMap, json['apiType']) ?? - APIType.rest, - name: json['name'] as String? ?? "", - description: json['description'] as String? ?? "", - requestTabIndex: json['requestTabIndex'] ?? 0, - httpRequestModel: json['httpRequestModel'] == null - ? null - : HttpRequestModel.fromJson( - Map.from(json['httpRequestModel'] as Map)), - responseStatus: (json['responseStatus'] as num?)?.toInt(), - message: json['message'] as String?, - httpResponseModel: json['httpResponseModel'] == null - ? null - : HttpResponseModel.fromJson( - Map.from(json['httpResponseModel'] as Map)), - isWorking: json['isWorking'] as bool? ?? false, - sendingTime: json['sendingTime'] == null - ? null - : DateTime.parse(json['sendingTime'] as String), - isStreaming: json['isStreaming'] as bool? ?? false, - preRequestScript: json['preRequestScript'] as String?, - postRequestScript: json['postRequestScript'] as String?, - aiRequestModel: json['aiRequestModel'] == null - ? null - : AIRequestModel.fromJson( - Map.from(json['aiRequestModel'] as Map)), - ); +_RequestModel _$RequestModelFromJson(Map json) => _RequestModel( + id: json['id'] as String, + apiType: + $enumDecodeNullable(_$APITypeEnumMap, json['apiType']) ?? APIType.rest, + name: json['name'] as String? ?? "", + description: json['description'] as String? ?? "", + requestTabIndex: json['requestTabIndex'] ?? 0, + httpRequestModel: json['httpRequestModel'] == null + ? null + : HttpRequestModel.fromJson( + Map.from(json['httpRequestModel'] as Map), + ), + responseStatus: (json['responseStatus'] as num?)?.toInt(), + message: json['message'] as String?, + httpResponseModel: json['httpResponseModel'] == null + ? null + : HttpResponseModel.fromJson( + Map.from(json['httpResponseModel'] as Map), + ), + isWorking: json['isWorking'] as bool? ?? false, + sendingTime: json['sendingTime'] == null + ? null + : DateTime.parse(json['sendingTime'] as String), + isStreaming: json['isStreaming'] as bool? ?? false, + preRequestScript: json['preRequestScript'] as String?, + postRequestScript: json['postRequestScript'] as String?, + aiRequestModel: json['aiRequestModel'] == null + ? null + : AIRequestModel.fromJson( + Map.from(json['aiRequestModel'] as Map), + ), + protocolModel: const ProtocolModelConverter().fromJson(json['protocolModel']), +); -Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => +Map _$RequestModelToJson(_RequestModel instance) => { 'id': instance.id, 'apiType': _$APITypeEnumMap[instance.apiType]!, @@ -49,10 +53,16 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'preRequestScript': instance.preRequestScript, 'postRequestScript': instance.postRequestScript, 'aiRequestModel': instance.aiRequestModel?.toJson(), + 'protocolModel': const ProtocolModelConverter().toJson( + instance.protocolModel, + ), }; const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.ai: 'ai', APIType.graphql: 'graphql', + APIType.websocket: 'websocket', + APIType.mqtt: 'mqtt', + APIType.grpc: 'grpc', }; diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 047b5b09ed..4ac0f15b0d 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -7,7 +8,15 @@ import 'package:apidash/consts.dart'; import 'package:apidash/terminal/terminal.dart'; import 'providers.dart'; import '../models/models.dart'; +import '../models/protocols/base_protocol_model.dart'; +import '../models/protocols/websocket_model.dart'; +import '../models/protocols/mqtt_model.dart'; +import '../models/protocols/grpc_model.dart'; + +import '../services/connection_manager.dart'; import '../services/services.dart'; +import '../services/grpc_reflection_service.dart'; +import 'package:mqtt_client/mqtt_client.dart'; import '../utils/utils.dart'; final selectedIdStateProvider = StateProvider((ref) => null); @@ -119,17 +128,27 @@ class CollectionStateNotifier void remove({String? id}) { final rId = id ?? ref.read(selectedIdStateProvider); + if (rId == null) return; var itemIds = ref.read(requestSequenceProvider); - int idx = itemIds.indexOf(rId!); + int idx = itemIds.indexOf(rId); + + // Cleanup of active connections + ConnectionManager.instance.disconnectWebSocket(rId); + ConnectionManager.instance.disconnectMqtt(rId); cancelHttpRequest(rId); + itemIds.remove(rId); ref.read(requestSequenceProvider.notifier).state = [...itemIds]; String? newId; - if (idx == 0 && itemIds.isNotEmpty) { - newId = itemIds[0]; - } else if (itemIds.length > 1) { - newId = itemIds[idx - 1]; + if (itemIds.isNotEmpty) { + if (idx == 0) { + newId = itemIds[0]; + } else if (idx < itemIds.length) { + newId = itemIds[idx]; + } else { + newId = itemIds.last; + } } else { newId = null; } @@ -142,6 +161,113 @@ class CollectionStateNotifier unsave(); } + void sendWebSocketMessage(String requestId, String message) { + final currentRequest = state?[requestId]; + if (currentRequest != null && currentRequest.apiType == APIType.websocket) { + final protocolModel = currentRequest.protocolModel; + if (protocolModel is WebSocketRequestModel) { + final wsModel = protocolModel; + try { + final channel = ConnectionManager.instance.getWebSocketChannel( + requestId, + ); + channel.sink.add(message); + + final newMessage = WebSocketMessage( + payload: message, + timestamp: DateTime.now(), + outgoing: true, + messageType: WebSocketMessageType.sent, + ); + + final updatedWsModel = wsModel.copyWith( + messageHistory: [...wsModel.messageHistory, newMessage], + ); + + update(id: requestId, protocolModel: updatedWsModel); + } catch (e) { + debugPrint("Error sending WS message: $e"); + } + } + } + } + + void sendMqttMessage(String requestId, String topic, String message) { + final currentRequest = state?[requestId]; + if (currentRequest != null && currentRequest.apiType == APIType.mqtt) { + final protocolModel = currentRequest.protocolModel; + if (protocolModel is MQTTRequestModel) { + final mqttModel = protocolModel; + try { + ConnectionManager.instance.publishMqtt( + requestId, + topic, + message, + mqttModel.qos, + ); + + final newMessage = WebSocketMessage( + payload: "Topic: $topic\nMessage: $message", + timestamp: DateTime.now(), + outgoing: true, + messageType: WebSocketMessageType.sent, + qos: mqttModel.qos, + ); + + final updatedMqttModel = mqttModel.copyWith( + messageHistory: [...mqttModel.messageHistory, newMessage], + ); + + update(id: requestId, protocolModel: updatedMqttModel); + } catch (e) { + debugPrint("Error sending MQTT message: $e"); + } + } + } + } + + void subscribeMqttTopic(String requestId, String topic, int qos) { + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is MQTTRequestModel) { + final mqttModel = currentRequest.protocolModel as MQTTRequestModel; + ConnectionManager.instance.subscribeMqtt(requestId, topic, qos); + + final logMsg = WebSocketMessage( + payload: "Subscribed to topic: $topic", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final updatedModel = mqttModel.copyWith( + messageHistory: [...mqttModel.messageHistory, logMsg], + ); + update(id: requestId, protocolModel: updatedModel, isWorking: false); + } + } + + void unsubscribeMqttTopic(String requestId, String topic) { + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is MQTTRequestModel) { + final mqttModel = currentRequest.protocolModel as MQTTRequestModel; + ConnectionManager.instance.unsubscribeMqtt(requestId, topic); + + final logMsg = WebSocketMessage( + payload: "Unsubscribed from topic: $topic", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final updatedModel = mqttModel.copyWith( + messageHistory: [...mqttModel.messageHistory, logMsg], + ); + update(id: requestId, protocolModel: updatedModel, isWorking: false); + } + } + void clearResponse({String? id}) { final rId = id ?? ref.read(selectedIdStateProvider); if (rId == null || state?[rId] == null) return; @@ -242,6 +368,9 @@ class CollectionStateNotifier String? preRequestScript, String? postRequestScript, AIRequestModel? aiRequestModel, + ProtocolModel? protocolModel, + bool? isStreaming, + bool? isWorking, }) { final rId = id ?? ref.read(selectedIdStateProvider); if (rId == null) { @@ -263,6 +392,7 @@ class CollectionStateNotifier description: description ?? currentModel.description, httpRequestModel: const HttpRequestModel(), aiRequestModel: null, + protocolModel: null, ), APIType.ai => currentModel.copyWith( apiType: apiType, @@ -273,6 +403,35 @@ class CollectionStateNotifier aiRequestModel: defaultModel == null ? const AIRequestModel() : AIRequestModel.fromJson(defaultModel), + protocolModel: null, + ), + APIType.websocket => currentModel.copyWith( + apiType: apiType, + requestTabIndex: 0, + name: name ?? currentModel.name, + description: description ?? currentModel.description, + httpRequestModel: null, + aiRequestModel: null, + protocolModel: const WebSocketRequestModel(url: ""), + ), + APIType.mqtt => currentModel.copyWith( + apiType: apiType, + requestTabIndex: 0, + name: name ?? currentModel.name, + description: description ?? currentModel.description, + httpRequestModel: null, + aiRequestModel: null, + protocolModel: const MQTTRequestModel(brokerUrl: "", port: 1883), + ), + + APIType.grpc => currentModel.copyWith( + apiType: apiType, + requestTabIndex: 0, + name: name ?? currentModel.name, + description: description ?? currentModel.description, + httpRequestModel: null, + aiRequestModel: null, + protocolModel: const GrpcRequestModel(host: ""), ), }; } else { @@ -298,12 +457,28 @@ class CollectionStateNotifier query: query ?? currentHttpRequestModel.query, formData: formData ?? currentHttpRequestModel.formData, ), + protocolModel: + protocolModel ?? + ((currentModel.protocolModel is GrpcRequestModel) + ? (currentModel.protocolModel as GrpcRequestModel).copyWith( + metadata: + headers ?? + (currentModel.protocolModel as GrpcRequestModel) + .metadata, + isMetadataEnabled: + isHeaderEnabledList ?? + (currentModel.protocolModel as GrpcRequestModel) + .isMetadataEnabled, + ) + : currentModel.protocolModel), responseStatus: responseStatus ?? currentModel.responseStatus, message: message ?? currentModel.message, httpResponseModel: httpResponseModel ?? currentModel.httpResponseModel, preRequestScript: preRequestScript ?? currentModel.preRequestScript, postRequestScript: postRequestScript ?? currentModel.postRequestScript, aiRequestModel: aiRequestModel ?? currentModel.aiRequestModel, + isStreaming: isStreaming ?? currentModel.isStreaming, + isWorking: isWorking ?? currentModel.isWorking, ); } @@ -323,7 +498,8 @@ class CollectionStateNotifier RequestModel? requestModel = state![requestId]; if (requestModel?.httpRequestModel == null && - requestModel?.aiRequestModel == null) { + requestModel?.aiRequestModel == null && + requestModel?.protocolModel == null) { return; } @@ -354,13 +530,52 @@ class CollectionStateNotifier APIType apiType = executionRequestModel.apiType; bool noSSL = ref.read(settingsProvider).isSSLDisabled; + + if (apiType == APIType.websocket) { + final protocolModel = requestModel.protocolModel; + if (protocolModel is WebSocketRequestModel) { + await _connectWebSocket(requestId, requestModel, protocolModel); + } else { + update(id: requestId, message: "Invalid WebSocket model"); + } + return; + } + + if (apiType == APIType.mqtt) { + final protocolModel = requestModel.protocolModel; + if (protocolModel is MQTTRequestModel) { + await _connectMqtt(requestId, requestModel, protocolModel); + } else { + update(id: requestId, message: "Invalid MQTT model"); + } + return; + } + + if (apiType == APIType.grpc) { + final protocolModel = requestModel.protocolModel; + if (protocolModel is GrpcRequestModel) { + await _connectGrpc(requestId, requestModel, protocolModel); + } else { + update(id: requestId, message: "Invalid gRPC model"); + } + return; + } + HttpRequestModel substitutedHttpRequestModel; if (apiType == APIType.ai) { + if (executionRequestModel.aiRequestModel?.httpRequestModel == null) { + update(id: requestId, message: "Invalid AI model"); + return; + } substitutedHttpRequestModel = getSubstitutedHttpRequestModel( executionRequestModel.aiRequestModel!.httpRequestModel!, ); } else { + if (executionRequestModel.httpRequestModel == null) { + update(id: requestId, message: "Invalid Request model"); + return; + } substitutedHttpRequestModel = getSubstitutedHttpRequestModel( executionRequestModel.httpRequestModel!, ); @@ -579,6 +794,42 @@ class CollectionStateNotifier void cancelRequest() { final id = ref.read(selectedIdStateProvider); + if (id == null) return; + + final requestModel = state?[id]; + final apiType = requestModel?.apiType; + + if (apiType == APIType.websocket) { + // Set streaming to false first so onDone doesn't trigger auto-reconnect + final map = {...state!}; + map[id] = requestModel!.copyWith(isWorking: false, isStreaming: false); + state = map; + + ConnectionManager.instance.disconnectWebSocket(id); + unsave(); + return; + } + + if (apiType == APIType.mqtt) { + final map = {...state!}; + map[id] = requestModel!.copyWith(isWorking: false, isStreaming: false); + state = map; + + ConnectionManager.instance.disconnectMqtt(id); + unsave(); + return; + } + + if (apiType == APIType.grpc) { + final map = {...state!}; + map[id] = requestModel!.copyWith(isWorking: false, isStreaming: false); + state = map; + + ConnectionManager.instance.disconnectGrpc(id); + unsave(); + return; + } + cancelHttpRequest(id); unsave(); } @@ -659,4 +910,434 @@ class CollectionStateNotifier return substituteHttpRequestModel(httpRequestModel, envMap, activeEnvId); } + + Future _connectWebSocket( + String requestId, + RequestModel requestModel, + WebSocketRequestModel wsModel, + ) async { + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: true, + sendingTime: DateTime.now(), + ), + }; + try { + final now = DateTime.now(); + final connMsg1 = WebSocketMessage( + payload: "Attempting to connect to ${wsModel.url}", + timestamp: now, + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + final connMsg2 = WebSocketMessage( + payload: "WebSocket channel created, waiting for connection...", + timestamp: now, + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final channel = await ConnectionManager.instance.connectWebSocket( + requestId, + wsModel, + ); + + final connMsg3 = WebSocketMessage( + payload: "Connected to ${wsModel.url}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final connectedWsModel = wsModel.copyWith( + messageHistory: [connMsg1, connMsg2, connMsg3], + ); + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: false, + isStreaming: true, + protocolModel: connectedWsModel, + ), + }; + + channel.stream.listen( + (data) { + final currentRequest = state?[requestId]; + if (currentRequest != null) { + final protocolModel = currentRequest.protocolModel; + if (protocolModel is WebSocketRequestModel) { + final newMessage = WebSocketMessage( + payload: data.toString(), + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.received, + ); + final updatedWsModel = protocolModel.copyWith( + messageHistory: [...protocolModel.messageHistory, newMessage], + ); + update(id: requestId, protocolModel: updatedWsModel); + } + } + }, + onError: (e) { + update(id: requestId, message: e.toString()); + }, + onDone: () async { + final currentRequest = state?[requestId]; + if (currentRequest == null || + currentRequest.protocolModel is! WebSocketRequestModel) + return; + + final ws = currentRequest.protocolModel as WebSocketRequestModel; + + // If it was a manual stop, isStreaming would already be or will be false. + // We check the state to see if we should attempt a reconnect. + if (ws.autoReconnect && currentRequest.isStreaming) { + final now = DateTime.now(); + final reconnectMsg = WebSocketMessage( + payload: + "Connection lost. Attempting to reconnect in 3 seconds...", + timestamp: now, + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + final updatedWsModel = ws.copyWith( + messageHistory: [...ws.messageHistory, reconnectMsg], + ); + update(id: requestId, protocolModel: updatedWsModel); + + await Future.delayed(const Duration(seconds: 3)); + + // Check again if we should still reconnect (user might have stopped it during the delay) + final latestReq = state?[requestId]; + if (latestReq != null && latestReq.isStreaming) { + _connectWebSocket(requestId, latestReq, updatedWsModel); + } + } else { + update(id: requestId, isStreaming: false); + } + }, + ); + } catch (e) { + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: false, + message: e.toString(), + ), + }; + } + } + + Future _connectMqtt( + String requestId, + RequestModel requestModel, + MQTTRequestModel mqttModel, + ) async { + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: true, + isStreaming: false, + sendingTime: DateTime.now(), + message: null, + ), + }; + try { + final now = DateTime.now(); + final connMsg1 = WebSocketMessage( + payload: "Attempting to connect to ${mqttModel.brokerUrl}", + timestamp: now, + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final client = await ConnectionManager.instance.connectMqtt( + requestId, + mqttModel, + ); + + final connMsg2 = WebSocketMessage( + payload: "Connected to ${mqttModel.brokerUrl}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final List subscriptionLogs = []; + // Subscribe to initial topics + for (int i = 0; i < mqttModel.subscribedTopics.length; i++) { + bool isEnabled = i < mqttModel.isTopicEnabledList.length + ? mqttModel.isTopicEnabledList[i] + : true; + if (isEnabled) { + final topic = mqttModel.subscribedTopics[i].name; + if (topic.isNotEmpty) { + ConnectionManager.instance.subscribeMqtt( + requestId, + topic, + mqttModel.qos, + ); + subscriptionLogs.add(WebSocketMessage( + payload: "Subscribed to topic: $topic", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + )); + } + } + } + + final updatedMqttModel = mqttModel.copyWith( + messageHistory: [connMsg1, connMsg2, ...subscriptionLogs], + ); + + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: false, + isStreaming: true, + protocolModel: updatedMqttModel, + ), + }; + + client.updates!.listen( + (List>? c) { + final recMess = c![0].payload as MqttPublishMessage; + final pt = MqttPublishPayload.bytesToStringAsString( + recMess.payload.message, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null) { + final protocolModel = currentRequest.protocolModel; + if (protocolModel is MQTTRequestModel) { + final newMessage = WebSocketMessage( + payload: "Topic: ${c[0].topic}\n$pt", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.received, + qos: recMess.header?.qos.index, + ); + final updatedModel = protocolModel.copyWith( + messageHistory: [...protocolModel.messageHistory, newMessage], + ); + update(id: requestId, protocolModel: updatedModel); + } + } + }, + onError: (e) { + update(id: requestId, message: e.toString()); + }, + onDone: () { + update(id: requestId, isStreaming: false); + }, + ); + } catch (e) { + final errorMsg = WebSocketMessage( + payload: "Connection Error: ${e.toString()}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.error, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is MQTTRequestModel) { + final currentMqttModel = + currentRequest.protocolModel as MQTTRequestModel; + final updatedModel = currentMqttModel.copyWith( + messageHistory: [...currentMqttModel.messageHistory, errorMsg], + ); + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: false, + message: e.toString(), + protocolModel: updatedModel, + ), + }; + } else { + state = { + ...state!, + requestId: requestModel.copyWith( + isWorking: false, + message: e.toString(), + ), + }; + } + } + } + + Future _connectGrpc( + String requestId, + RequestModel requestModel, + GrpcRequestModel grpcModel, + ) async { + try { + update(id: requestId, isWorking: true); + await ConnectionManager.instance.connectGrpc(requestId, grpcModel); + + final msg = WebSocketMessage( + payload: "Connected to gRPC host: ${grpcModel.host}:${grpcModel.port}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.connected, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is GrpcRequestModel) { + final currentGrpcModel = + currentRequest.protocolModel as GrpcRequestModel; + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: (grpcModel.service != null && grpcModel.method != null), + isStreaming: true, + protocolModel: currentGrpcModel.copyWith( + messageHistory: [msg], + ), + ), + }; + + print("gRPC: Host established. Checking for method invocation..."); + // Invoke method + if (grpcModel.service != null && grpcModel.method != null) { + print( + "gRPC: Invoking method ${grpcModel.service}/${grpcModel.method}", + ); + + GrpcMethodSchema? methodSchema; + if (grpcModel.useReflection) { + methodSchema = await GrpcReflectionService.getMethodSchema( + requestId, grpcModel, grpcModel.service!, grpcModel.method!); + } + + final startTime = DateTime.now(); + final requestData = grpcModel.parameters.isNotEmpty + ? GrpcUtils.paramsToBytes(grpcModel.parameters) + : utf8.encode(grpcModel.requestBody); + + final call = ConnectionManager.instance.callGrpcMethod( + requestId, + grpcModel.service!, + grpcModel.method!, + requestData, + metadata: grpcModel.metadataMap, + ); + + call.listen( + (data) { + final duration = DateTime.now().difference(startTime); + final payload = GrpcUtils.decodeBinaryResponse(data, schema: methodSchema); + final responseMsg = WebSocketMessage( + payload: + "Response (${duration.inMilliseconds}ms):\n$payload", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.received, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null) { + final protocolModel = currentRequest.protocolModel; + if (protocolModel is GrpcRequestModel) { + final receivedCount = protocolModel.messageHistory + .where( + (m) => m.messageType == WebSocketMessageType.received, + ) + .length; + + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: false, + isStreaming: false, + responseStatus: receivedCount == 0 ? 200 : null, + httpResponseModel: receivedCount == 0 + ? HttpResponseModel(body: payload, time: duration) + : currentRequest.httpResponseModel, + protocolModel: protocolModel.copyWith( + messageHistory: [ + ...protocolModel.messageHistory, + responseMsg, + ], + ), + ), + }; + } + } + }, + onDone: () { + final currentRequest = state?[requestId]; + if (currentRequest != null) { + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: false, + isStreaming: false, + ), + }; + } + }, + onError: (e) { + final errorMsg = WebSocketMessage( + payload: "RPC Error: ${e.toString()}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.error, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is GrpcRequestModel) { + final currentGrpcModel = + currentRequest.protocolModel as GrpcRequestModel; + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: false, + isStreaming: false, + protocolModel: currentGrpcModel.copyWith( + messageHistory: [ + ...currentGrpcModel.messageHistory, + errorMsg, + ], + ), + ), + }; + } + }, + ); + } + } + } catch (e) { + final errorMsg = WebSocketMessage( + payload: "Connection Error: ${e.toString()}", + timestamp: DateTime.now(), + outgoing: false, + messageType: WebSocketMessageType.error, + ); + + final currentRequest = state?[requestId]; + if (currentRequest != null && + currentRequest.protocolModel is GrpcRequestModel) { + final currentGrpcModel = + currentRequest.protocolModel as GrpcRequestModel; + state = { + ...state!, + requestId: currentRequest.copyWith( + isWorking: false, + message: e.toString(), + protocolModel: currentGrpcModel.copyWith( + messageHistory: [...currentGrpcModel.messageHistory, errorMsg], + ), + ), + }; + } + } + } } diff --git a/lib/screens/common_widgets/envfield_url.dart b/lib/screens/common_widgets/envfield_url.dart index 4757c870c9..a0d9d2a5ab 100644 --- a/lib/screens/common_widgets/envfield_url.dart +++ b/lib/screens/common_widgets/envfield_url.dart @@ -11,6 +11,7 @@ class EnvURLField extends StatelessWidget { this.onChanged, this.onFieldSubmitted, this.focusNode, + this.hintText, }); final String selectedId; @@ -18,6 +19,7 @@ class EnvURLField extends StatelessWidget { final void Function(String)? onChanged; final void Function(String)? onFieldSubmitted; final FocusNode? focusNode; + final String? hintText; @override Widget build(BuildContext context) { @@ -27,7 +29,7 @@ class EnvURLField extends StatelessWidget { focusNode: focusNode, style: kCodeStyle, decoration: InputDecoration( - hintText: kHintTextUrlCard, + hintText: hintText ?? kHintTextUrlCard, hintStyle: kCodeStyle.copyWith( color: Theme.of(context).colorScheme.outlineVariant, ), diff --git a/lib/screens/home_page/editor_pane/details_card/event_stream_view.dart b/lib/screens/home_page/editor_pane/details_card/event_stream_view.dart new file mode 100644 index 0000000000..6a97364050 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/event_stream_view.dart @@ -0,0 +1,234 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/models/protocols/websocket_model.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; + +/// A log-style event stream view +class EventStreamView extends ConsumerWidget { + const EventStreamView({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final requestModel = ref.watch(selectedRequestModelProvider); + final apiType = requestModel?.apiType; + + if (apiType == APIType.websocket) { + final protocolModel = requestModel?.protocolModel; + final wsModel = protocolModel is WebSocketRequestModel ? protocolModel : null; + final history = wsModel?.messageHistory ?? []; + + return Column( + children: [ + // Header bar: connection status + clear button + _StreamStatusBar( + title: "Connected to WebSocket server", + hasMessages: history.isNotEmpty, + onClear: () { + if (wsModel != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: wsModel.copyWith(messageHistory: []), + ); + } + }, + ), + const Divider(height: 1), + // Log content + Expanded( + child: history.isEmpty + ? const Center( + child: Text( + "No messages yet. Connect to start.", + style: TextStyle(color: Colors.grey), + ), + ) + : _buildLogView(context, history), + ), + ], + ); + } + + if (apiType == APIType.mqtt) { + final protocolModel = requestModel?.protocolModel; + final mqttModel = protocolModel is MQTTRequestModel ? protocolModel : null; + final history = mqttModel?.messageHistory ?? []; + + return Column( + children: [ + _StreamStatusBar( + title: "Connected to MQTT Broker", + hasMessages: history.isNotEmpty, + onClear: () { + if (mqttModel != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(messageHistory: []), + ); + } + }, + ), + const Divider(height: 1), + Expanded( + child: history.isEmpty + ? const Center( + child: Text( + "No messages yet. Connect to start.", + style: TextStyle(color: Colors.grey), + ), + ) + : _buildLogView(context, history), + ), + ], + ); + } + + if (apiType == APIType.grpc) { + final protocolModel = requestModel?.protocolModel; + final grpcModel = protocolModel is GrpcRequestModel ? protocolModel : null; + final history = grpcModel?.messageHistory ?? []; + + return Column( + children: [ + _StreamStatusBar( + title: "gRPC Invocation Status", + hasMessages: history.isNotEmpty, + onClear: () { + if (grpcModel != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: grpcModel.copyWith(messageHistory: []), + ); + } + }, + ), + const Divider(height: 1), + Expanded( + child: history.isEmpty + ? const Center( + child: Text( + "No call made yet.", + style: TextStyle(color: Colors.grey), + ), + ) + : _buildLogView(context, history), + ), + ], + ); + } + + return kSizedBoxEmpty; + } + + Widget _buildLogView(BuildContext context, List history) { + return ListView.builder( + itemCount: history.length, + padding: const EdgeInsets.symmetric(vertical: 4), + itemBuilder: (context, index) { + final msg = history[index]; + return _WsLogEntry(msg: msg); + }, + ); + } +} + +class _StreamStatusBar extends StatelessWidget { + const _StreamStatusBar({ + required this.title, + required this.hasMessages, + required this.onClear, + }); + final String title; + final bool hasMessages; + final VoidCallback onClear; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: Row( + children: [ + Icon(Icons.circle, size: 8, color: Colors.green.shade400), + kHSpacer5, + Text( + title, + style: kCodeStyle.copyWith( + fontSize: 13, + color: Colors.green.shade400, + fontWeight: FontWeight.w600, + ), + ), + const Spacer(), + if (hasMessages) + IconButton( + icon: const Icon(Icons.delete_outline, size: 18), + tooltip: "Clear messages", + onPressed: onClear, + ), + ], + ), + ); + } +} + +class _WsLogEntry extends StatelessWidget { + const _WsLogEntry({required this.msg}); + final WebSocketMessage msg; + + @override + Widget build(BuildContext context) { + final time = msg.timestamp != null + ? "${msg.timestamp!.hour.toString().padLeft(2, '0')}:" + "${msg.timestamp!.minute.toString().padLeft(2, '0')}:" + "${msg.timestamp!.second.toString().padLeft(2, '0')}" + : ""; + + final (Color labelColor, String labelText, IconData dirIcon) = + switch (msg.messageType) { + WebSocketMessageType.connected => (Colors.teal.shade400, "Connected", Icons.link), + WebSocketMessageType.sent => (Colors.blue.shade400, "Sent", Icons.arrow_upward), + WebSocketMessageType.received => (Colors.green.shade400, "Received", Icons.arrow_downward), + WebSocketMessageType.error => (Colors.red.shade400, "Error", Icons.error_outline), + }; + + return InkWell( + onTap: () { + Clipboard.setData(ClipboardData(text: msg.payload)); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text("Copied to clipboard"), duration: Duration(milliseconds: 600)), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), + child: SelectableText.rich( + TextSpan( + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon(dirIcon, size: 14, color: labelColor), + ), + const TextSpan(text: " "), + TextSpan( + text: "[$time] ", + style: kCodeStyle.copyWith(fontSize: 12, color: Colors.grey), + ), + TextSpan( + text: "[$labelText] - ", + style: kCodeStyle.copyWith( + fontSize: 12, + color: labelColor, + fontWeight: FontWeight.bold, + ), + ), + TextSpan( + text: msg.payload, + style: kCodeStyle.copyWith(fontSize: 12), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_metadata_grpc.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_metadata_grpc.dart new file mode 100644 index 0000000000..f85c66da70 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_metadata_grpc.dart @@ -0,0 +1,229 @@ +import 'dart:math'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/consts.dart'; +import 'package:apidash/screens/common_widgets/common_widgets.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; + +class EditGrpcRequestMetadata extends ConsumerStatefulWidget { + const EditGrpcRequestMetadata({super.key}); + + @override + ConsumerState createState() => EditGrpcRequestMetadataState(); +} + +class EditGrpcRequestMetadataState extends ConsumerState { + late int seed; + final random = Random.secure(); + late List metadataRows; + late List isRowEnabledList; + bool isAddingRow = false; + + @override + void initState() { + super.initState(); + seed = random.nextInt(kRandMax); + } + + void _onFieldChange() { + ref.read(collectionStateNotifierProvider.notifier).update( + headers: metadataRows.sublist(0, metadataRows.length - 1), + isHeaderEnabledList: + isRowEnabledList.sublist(0, metadataRows.length - 1), + ); + } + + @override + Widget build(BuildContext context) { + dataTableShowLogs = false; + final selectedId = ref.watch(selectedIdStateProvider); + final requestModel = ref.watch(selectedRequestModelProvider); + final protocolModel = requestModel?.protocolModel; + final grpcModel = protocolModel is GrpcRequestModel ? protocolModel : null; + + if (grpcModel == null) return kSizedBoxEmpty; + + var rH = grpcModel.metadata; + bool isMetadataEmpty = rH == null || rH.isEmpty; + metadataRows = isMetadataEmpty + ? [ + kNameValueEmptyModel, + ] + : rH + [kNameValueEmptyModel]; + isRowEnabledList = [ + ...(grpcModel.isMetadataEnabled ?? + List.filled(rH?.length ?? 0, true, growable: true)) + ]; + isRowEnabledList.add(false); + isAddingRow = false; + + List columns = const [ + DataColumn2( + label: Text(kNameCheckbox), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameHeader), + ), + DataColumn2( + label: Text('='), + fixedWidth: 30, + ), + DataColumn2( + label: Text(kNameValue), + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + metadataRows.length, + (index) { + bool isLast = index + 1 == metadataRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-grpc-metadata-row-$seed"), + cells: [ + DataCell( + ADCheckBox( + keyId: "$selectedId-$index-grpc-metadata-c-$seed", + value: isRowEnabledList[index], + onChanged: isLast + ? null + : (value) { + setState(() { + isRowEnabledList[index] = value!; + }); + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + EnvHeaderField( + keyId: "$selectedId-$index-grpc-metadata-k-$seed", + initialValue: metadataRows[index].name, + hintText: kHintAddName, + onChanged: (value) { + metadataRows[index] = metadataRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + metadataRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + Center( + child: Text( + "=", + style: kCodeStyle, + ), + ), + ), + DataCell( + EnvCellField( + keyId: "$selectedId-$index-grpc-metadata-v-$seed", + initialValue: metadataRows[index].value, + hintText: kHintAddValue, + onChanged: (value) { + metadataRows[index] = metadataRows[index].copyWith(value: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + isRowEnabledList[index] = true; + metadataRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(); + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + if (metadataRows.length == 2) { + setState(() { + metadataRows = [ + kNameValueEmptyModel, + ]; + isRowEnabledList = [false]; + }); + } else { + metadataRows.removeAt(index); + isRowEnabledList.removeAt(index); + } + _onFieldChange(); + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, + ); + + return Stack( + children: [ + Container( + margin: kPh10t10, + child: Column( + children: [ + Expanded( + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), + ), + ), + if (!kIsMobile) kVSpacer40, + ], + ), + ), + if (!kIsMobile) + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: kPb15, + child: ElevatedButton.icon( + onPressed: () { + metadataRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + _onFieldChange(); + }, + icon: const Icon(Icons.add), + label: const Text( + "Add Metadata", + style: kTextStyleButton, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart index abddbaa7de..434c8ecdd6 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane.dart @@ -11,6 +11,10 @@ import '../response_pane.dart'; import 'ai_request/request_pane_ai.dart'; import 'request_pane_graphql.dart'; import 'request_pane_rest.dart'; +import 'request_pane_ws.dart'; +import 'request_pane_mqtt.dart'; +import 'request_pane_grpc.dart'; + class EditRequestPane extends ConsumerWidget { const EditRequestPane({ @@ -61,6 +65,16 @@ class EditRequestPane extends ConsumerWidget { APIType.ai => EditAIRequestPane( showViewCodeButton: false, ), + APIType.websocket => EditWSRequestPane( + showViewCodeButton: false, + ), + APIType.mqtt => EditMQTTRequestPane( + showViewCodeButton: false, + ), + APIType.grpc => EditGrpcRequestPane( + showViewCodeButton: false, + ), + _ => kSizedBoxEmpty, }, ResponsePane(), @@ -86,6 +100,16 @@ class EditRequestPane extends ConsumerWidget { APIType.ai => EditAIRequestPane( showViewCodeButton: showViewCodeButton, ), + APIType.websocket => EditWSRequestPane( + showViewCodeButton: showViewCodeButton, + ), + APIType.mqtt => EditMQTTRequestPane( + showViewCodeButton: showViewCodeButton, + ), + APIType.grpc => EditGrpcRequestPane( + showViewCodeButton: showViewCodeButton, + ), + _ => kSizedBoxEmpty, }; } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_grpc.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_grpc.dart new file mode 100644 index 0000000000..7c77bbdb64 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_grpc.dart @@ -0,0 +1,425 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:apidash/services/connection_manager.dart'; +import 'package:apidash/utils/grpc_utils.dart'; +import 'package:apidash/services/grpc_reflection_service.dart'; +import 'request_metadata_grpc.dart'; +import 'request_parameters_grpc.dart'; + +class EditGrpcRequestPane extends ConsumerStatefulWidget { + const EditGrpcRequestPane({ + super.key, + this.showViewCodeButton = true, + }); + + final bool showViewCodeButton; + + @override + ConsumerState createState() => + _EditGrpcRequestPaneState(); +} + +class _EditGrpcRequestPaneState extends ConsumerState { + final TextEditingController _bodyController = TextEditingController(); + + @override + void dispose() { + _bodyController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final requestModel = ref.watch(selectedRequestModelProvider); + final protocolModel = requestModel?.protocolModel; + final grpcModel = protocolModel is GrpcRequestModel ? protocolModel : null; + + if (grpcModel == null) return kSizedBoxEmpty; + + if (_bodyController.text != grpcModel.requestBody) { + _bodyController.text = grpcModel.requestBody; + } + + return DefaultTabController( + length: 4, + child: Column( + children: [ + TabBar( + labelColor: Theme.of(context).colorScheme.primary, + unselectedLabelColor: + Theme.of(context).colorScheme.onSurfaceVariant, + tabs: const [ + Tab(text: "Invocation"), + Tab(text: "Body"), + Tab(text: "Metadata"), + Tab(text: "Settings"), + ], + ), + Expanded( + child: TabBarView( + children: [ + // Invocation Tab + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: DropdownButtonFormField( + value: grpcModel.service, + decoration: const InputDecoration( + labelText: "Select Service", + border: OutlineInputBorder(), + ), + isExpanded: true, + items: grpcModel.availableServices.map((s) { + return DropdownMenuItem( + value: s, + child: Text(s), + ); + }).toList(), + onChanged: (val) async { + if (val != null) { + List methods = []; + if (grpcModel.useReflection && requestModel != null) { + await ConnectionManager.instance + .connectGrpc(requestModel.id, grpcModel); + final result = await GrpcReflectionService + .getMethodsForService( + requestModel.id, grpcModel, val); + methods = result[val] ?? []; + } + ref + .read(collectionStateNotifierProvider + .notifier) + .update( + protocolModel: grpcModel.copyWith( + service: val, + availableMethods: methods, + method: null, + ), + ); + } + }, + ), + ), + kHSpacer20, + Expanded( + child: DropdownButtonFormField( + isExpanded: true, + value: grpcModel.method, + decoration: const InputDecoration( + labelText: "Select Method", + border: OutlineInputBorder(), + ), + items: grpcModel.availableMethods.map((m) { + return DropdownMenuItem( + value: m, + child: Text(m), + ); + }).toList(), + onChanged: (val) async { + if (val != null) { + List params = []; + if (grpcModel.protoFile != null) { + final result = await GrpcUtils.parseProtoFile( + grpcModel.protoFile!); + final methodMappings = + result['methods'] as Map?; + final messageFields = result['messageFields'] + as Map?; + + if (methodMappings != null && + messageFields != null) { + final requestType = + (methodMappings["${grpcModel.service}/$val"] + as List?)?.first; + if (requestType != null) { + params = (messageFields[requestType] + as List?) ?? + []; + } + } + } else if (grpcModel.useReflection && + requestModel != null && + grpcModel.service != null) { + params = await GrpcReflectionService + .getParamsForMethod( + requestModel.id, + grpcModel, + grpcModel.service!, + val); + } + + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: grpcModel.copyWith( + method: val, + parameters: params, + requestBody: GrpcUtils.paramsToJson(params), + ), + ); + } + }, + ), + ), + ], + ), + kVSpacer20, + const Text("Request Parameters (Form)", + style: kTextStyleButtonSmall), + kVSpacer10, + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.outlineVariant), + borderRadius: BorderRadius.circular(8), + ), + child: const EditGrpcRequestParameters(), + ), + ), + ], + ), + ), + // Body Tab + Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Request Body (JSON)", + style: kTextStyleButtonSmall), + kVSpacer10, + Expanded( + flex: 1, + child: TextField( + controller: _bodyController, + maxLines: null, + expands: true, + textAlignVertical: TextAlignVertical.top, + style: kCodeStyle, + decoration: InputDecoration( + hintText: "Enter request body (JSON)...", + hintStyle: kCodeStyle, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (val) { + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: + grpcModel.copyWith(requestBody: val), + ); + }, + ), + ), + ], + ), + ), + // Metadata Tab + const EditGrpcRequestMetadata(), + // Settings Tab + Padding( + padding: const EdgeInsets.all(16), + child: ListView( + children: [ + Row( + children: [ + const Text("Port: "), + SizedBox( + width: 100, + child: TextFormField( + initialValue: grpcModel.port.toString(), + decoration: const InputDecoration( + isDense: true, + border: OutlineInputBorder(), + ), + keyboardType: TextInputType.number, + onChanged: (val) { + final port = int.tryParse(val.trim()) ?? 50051; + ref + .read(collectionStateNotifierProvider + .notifier) + .update( + protocolModel: + grpcModel.copyWith(port: port), + ); + }, + ), + ), + ], + ), + kVSpacer20, + SwitchListTile( + title: const Text("Use TLS"), + value: grpcModel.useTLS, + onChanged: (val) { + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: grpcModel.copyWith(useTLS: val), + ); + }, + ), + kVSpacer20, + SwitchListTile( + title: const Text("Use Reflection"), + subtitle: const Text("Discover services from server"), + value: grpcModel.useReflection, + onChanged: (val) { + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: + grpcModel.copyWith(useReflection: val), + ); + }, + ), + kVSpacer20, + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Proto File", + style: kTextStyleButtonSmall), + Text( + grpcModel.protoFile ?? + "No Proto file selected", + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), + ), + ElevatedButton.icon( + onPressed: () async { + const XTypeGroup typeGroup = XTypeGroup( + label: 'Proto Files', + extensions: ['proto'], + ); + final XFile? file = await openFile( + acceptedTypeGroups: [typeGroup]); + if (file != null) { + ref + .read(collectionStateNotifierProvider + .notifier) + .update( + protocolModel: grpcModel.copyWith( + protoFile: file.path), + ); + } + }, + icon: const Icon(Icons.file_open), + label: const Text("Select .proto"), + ), + ], + ), + kVSpacer20, + ElevatedButton.icon( + onPressed: () async { + if (grpcModel.useReflection && requestModel != null) { + // Ensure connected + await ConnectionManager.instance + .connectGrpc(requestModel.id, grpcModel); + + print("Calling listServices now..."); + final services = + await GrpcReflectionService.listServices( + requestModel.id, grpcModel); + List methods = []; + if (services.isNotEmpty) { + final res = await GrpcReflectionService + .getMethodsForService(requestModel.id, + grpcModel, services.first); + methods = res[services.first] ?? []; + } + + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: grpcModel.copyWith( + availableServices: services, + service: services.isNotEmpty + ? services.first + : null, + availableMethods: methods, + parameters: [], + ), + ); + } else if (grpcModel.protoFile != null) { + final result = await GrpcUtils.parseProtoFile( + grpcModel.protoFile!); + final services = + (result['services'] as List?) ?? []; + final methods = + (result['methods'] as Map?) ?? {}; + + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: grpcModel.copyWith( + availableServices: services, + service: services.isNotEmpty + ? services.first + : null, + availableMethods: services.isNotEmpty + ? (methods[services.first] + as List?) ?? + [] + : [], + method: null, + parameters: [], + ), + ); + } else { + // Mocking fallback + ref + .read(collectionStateNotifierProvider.notifier) + .update( + protocolModel: grpcModel.copyWith( + availableServices: [ + "helloworld.Greeter", + "echo.EchoService" + ], + availableMethods: [ + "SayHello", + "SayGoodbye", + "Echo" + ], + parameters: [ + const GrpcParameterModel( + name: "name", type: "string"), + const GrpcParameterModel( + name: "age", type: "int32"), + ], + ), + ); + } + }, + icon: const Icon(Icons.refresh), + label: const Text("Fetch Services"), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_mqtt.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_mqtt.dart new file mode 100644 index 0000000000..860258320f --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_mqtt.dart @@ -0,0 +1,258 @@ +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; +import 'request_topics_mqtt.dart'; + +class EditMQTTRequestPane extends ConsumerStatefulWidget { + const EditMQTTRequestPane({ + super.key, + this.showViewCodeButton = true, + }); + + final bool showViewCodeButton; + + @override + ConsumerState createState() => _EditMQTTRequestPaneState(); +} + +class _EditMQTTRequestPaneState extends ConsumerState { + final TextEditingController _messageController = TextEditingController(); + + @override + void dispose() { + _messageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final selectedId = ref.watch(selectedIdStateProvider); + final requestModel = ref.watch(selectedRequestModelProvider); + final protocolModel = requestModel?.protocolModel; + final mqttModel = protocolModel is MQTTRequestModel ? protocolModel : null; + + if (mqttModel == null) return kSizedBoxEmpty; + + // Sync controllers if model changes from outside (e.g. selection) + if (_messageController.text != mqttModel.message) { + _messageController.text = mqttModel.message; + } + + return DefaultTabController( + length: 4, + child: Column( + children: [ + TabBar( + labelColor: Theme.of(context).colorScheme.primary, + unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant, + tabs: const [ + Tab(text: "Message"), + Tab(text: "Auth"), + Tab(text: "Settings"), + Tab(text: "Topics"), + ], + ), + Expanded( + child: TabBarView( + children: [ + // Message Tab + Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Autocomplete( + initialValue: TextEditingValue(text: mqttModel.publishTopic), + optionsBuilder: (TextEditingValue textEditingValue) { + if (textEditingValue.text.isEmpty) { + return mqttModel.subscribedTopics + .map((e) => e.name) + .where((e) => e.isNotEmpty); + } + return mqttModel.subscribedTopics + .map((e) => e.name) + .where((e) => e.isNotEmpty && e.toLowerCase().contains(textEditingValue.text.toLowerCase())); + }, + onSelected: (String selection) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(publishTopic: selection), + ); + }, + fieldViewBuilder: (context, controller, focusNode, onFieldSubmitted) { + // Sync internal controller with model if needed + // But better to just use this controller for the field + if (controller.text != mqttModel.publishTopic) { + controller.text = mqttModel.publishTopic; + } + + return TextField( + controller: controller, + focusNode: focusNode, + decoration: const InputDecoration( + labelText: "Send to topic:", + border: UnderlineInputBorder(), + ), + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(publishTopic: val), + ); + }, + ); + }, + ), + kVSpacer20, + Expanded( + child: TextField( + controller: _messageController, + maxLines: null, + expands: true, + textAlignVertical: TextAlignVertical.top, + style: kCodeStyle, + decoration: InputDecoration( + hintText: "Enter message...", + hintStyle: kCodeStyle, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(message: val), + ); + }, + ), + ), + kVSpacer20, + ElevatedButton( + onPressed: (requestModel?.isStreaming ?? false) ? () { + if (selectedId != null && mqttModel.publishTopic.isNotEmpty) { + ref.read(collectionStateNotifierProvider.notifier).sendMqttMessage( + selectedId, + mqttModel.publishTopic, + mqttModel.message, + ); + } + } : null, + child: const Text("Publish"), + ), + ], + ), + ), + // Auth Tab + Padding( + padding: const EdgeInsets.all(16), + child: ListView( + children: [ + TextFormField( + initialValue: mqttModel.username, + decoration: const InputDecoration(labelText: "Username"), + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(username: val), + ); + }, + ), + TextFormField( + initialValue: mqttModel.password, + obscureText: true, + decoration: const InputDecoration(labelText: "Password"), + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(password: val), + ); + }, + ), + ], + ), + ), + // Settings Tab + Padding( + padding: const EdgeInsets.all(16), + child: ListView( + children: [ + TextFormField( + initialValue: mqttModel.clientId, + decoration: const InputDecoration(labelText: "Client ID"), + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(clientId: val), + ); + }, + ), + TextFormField( + initialValue: mqttModel.port.toString(), + decoration: const InputDecoration(labelText: "Port"), + keyboardType: TextInputType.number, + onChanged: (val) { + final port = int.tryParse(val) ?? 1883; + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(port: port), + ); + }, + ), + DropdownButtonFormField( + value: mqttModel.qos, + decoration: const InputDecoration(labelText: "Default QoS"), + items: [0, 1, 2].map((q) { + return DropdownMenuItem( + value: q, + child: Text("QoS $q"), + ); + }).toList(), + onChanged: (val) { + if (val != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(qos: val), + ); + } + }, + ), + DropdownButtonFormField( + value: mqttModel.version, + decoration: const InputDecoration(labelText: "MQTT Version"), + items: MQTTVersion.values.map((v) { + return DropdownMenuItem( + value: v, + child: Text(v.name.toUpperCase().replaceAll("_", ".")), + ); + }).toList(), + onChanged: (val) { + if (val != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(version: val), + ); + } + }, + ), + SwitchListTile( + title: const Text("Use TLS"), + value: mqttModel.useTLS, + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(useTLS: val), + ); + }, + ), + SwitchListTile( + title: const Text("Use WebSocket"), + value: mqttModel.useWebSocket, + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith(useWebSocket: val), + ); + }, + ), + ], + ), + ), + // Topic Subscriptions Tab + const EditMQTTTopics(), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_ws.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_ws.dart new file mode 100644 index 0000000000..0a81decc57 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_ws.dart @@ -0,0 +1,144 @@ +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/models/protocols/websocket_model.dart'; + +class EditWSRequestPane extends ConsumerStatefulWidget { + const EditWSRequestPane({ + super.key, + this.showViewCodeButton = true, + }); + + final bool showViewCodeButton; + + @override + ConsumerState createState() => _EditWSRequestPaneState(); +} + +class _EditWSRequestPaneState extends ConsumerState { + final TextEditingController _controller = TextEditingController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final selectedId = ref.watch(selectedIdStateProvider); + final requestModel = ref.watch(selectedRequestModelProvider); + final protocolModel = requestModel?.protocolModel; + final wsModel = protocolModel is WebSocketRequestModel ? protocolModel : null; + + if (wsModel == null) return kSizedBoxEmpty; + + return DefaultTabController( + length: 4, + child: Column( + children: [ + TabBar( + labelColor: Theme.of(context).colorScheme.primary, + unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant, + tabs: const [ + Tab(text: "Message"), + Tab(text: "Headers"), + Tab(text: "Params"), + Tab(text: "Settings"), + ], + ), + Expanded( + child: TabBarView( + children: [ + // Message Tab + Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Expanded( + child: TextField( + controller: _controller, + maxLines: null, + expands: true, + textAlignVertical: TextAlignVertical.top, + style: kCodeStyle, + decoration: InputDecoration( + hintText: "Enter message...", + hintStyle: kCodeStyle, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ), + kVSpacer10, + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + OutlinedButton( + onPressed: () { + final value = _controller.text; + if (value.isNotEmpty) { + ref.read(collectionStateNotifierProvider.notifier).sendWebSocketMessage(selectedId!, value); + _controller.clear(); + } + }, + child: const Text("Send"), + ), + ], + ), + ], + ), + ), + // Headers Tab + Padding( + padding: kP8, + child: ListView.builder( + itemCount: wsModel.customHeaders.length + 1, + itemBuilder: (context, index) { + if (index == wsModel.customHeaders.length) { + return ListTile( + title: const Text("Add Header"), + trailing: const Icon(Icons.add), + onTap: () { + // Add header logic + }, + ); + } + final key = wsModel.customHeaders.keys.elementAt(index); + return ListTile( + title: Text(key), + subtitle: Text(wsModel.customHeaders[key] ?? ""), + ); + }, + ), + ), + // Params Tab + const Center(child: Text("URL Parameters")), + // Settings Tab + Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + SwitchListTile( + title: const Text("Auto Reconnect"), + value: wsModel.autoReconnect, + onChanged: (val) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: wsModel.copyWith(autoReconnect: val), + ); + }, + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} + diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_parameters_grpc.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_parameters_grpc.dart new file mode 100644 index 0000000000..33c71eb0fd --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_parameters_grpc.dart @@ -0,0 +1,95 @@ +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; +import 'package:apidash/utils/grpc_utils.dart'; + +class EditGrpcRequestParameters extends ConsumerWidget { + const EditGrpcRequestParameters({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final requestModel = ref.watch(selectedRequestModelProvider); + final protocolModel = requestModel?.protocolModel; + final grpcModel = protocolModel is GrpcRequestModel ? protocolModel : null; + + if (grpcModel == null || grpcModel.parameters.isEmpty) { + return const Center( + child: Padding( + padding: EdgeInsets.all(16.0), + child: Text("No parameters defined for this method."), + ), + ); + } + + return ListView.builder( + itemCount: grpcModel.parameters.length, + itemBuilder: (context, index) { + final param = grpcModel.parameters[index]; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + children: [ + Expanded( + flex: 2, + child: Text( + param.name, + style: kTextStyleButtonSmall.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + const Text(" : "), + Expanded( + flex: 5, + child: _buildParamInput(context, ref, grpcModel, index, param), + ), + ], + ), + ); + }, + ); + } + + Widget _buildParamInput(BuildContext context, WidgetRef ref, + GrpcRequestModel grpcModel, int index, GrpcParameterModel param) { + switch (param.type) { + case "bool": + return Switch( + value: param.value.toLowerCase() == "true", + onChanged: (val) => _updateParamValue(ref, grpcModel, index, val.toString()), + ); + case "enum": + return DropdownButtonFormField( + value: param.value.isEmpty ? (param.enumValues?.first) : param.value, + items: param.enumValues?.map((e) { + return DropdownMenuItem(value: e, child: Text(e)); + }).toList(), + onChanged: (val) => _updateParamValue(ref, grpcModel, index, val ?? ""), + ); + default: + return TextFormField( + initialValue: param.value, + decoration: InputDecoration( + hintText: "Enter ${param.type}...", + border: const OutlineInputBorder(), + contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + ), + onChanged: (val) => _updateParamValue(ref, grpcModel, index, val), + ); + } + } + + void _updateParamValue( + WidgetRef ref, GrpcRequestModel grpcModel, int index, String value) { + final newParams = List.from(grpcModel.parameters); + newParams[index] = newParams[index].copyWith(value: value); + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: grpcModel.copyWith( + parameters: newParams, + requestBody: GrpcUtils.paramsToJson(newParams), + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_topics_mqtt.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_topics_mqtt.dart new file mode 100644 index 0000000000..c7ceb064bd --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_topics_mqtt.dart @@ -0,0 +1,227 @@ +import 'dart:math'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:apidash/providers/providers.dart'; +import 'package:apidash/consts.dart'; +import 'package:apidash/screens/common_widgets/common_widgets.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; + +class EditMQTTTopics extends ConsumerStatefulWidget { + const EditMQTTTopics({super.key}); + + @override + ConsumerState createState() => EditMQTTTopicsState(); +} + +class EditMQTTTopicsState extends ConsumerState { + late int seed; + final random = Random.secure(); + late List topicRows; + late List isRowEnabledList; + bool isAddingRow = false; + + @override + void initState() { + super.initState(); + seed = random.nextInt(kRandMax); + } + + void _onFieldChange() { + final requestModel = ref.read(selectedRequestModelProvider); + final mqttModel = requestModel?.protocolModel as MQTTRequestModel?; + if (mqttModel != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: mqttModel.copyWith( + subscribedTopics: topicRows.sublist(0, topicRows.length - 1), + isTopicEnabledList: isRowEnabledList.sublist(0, topicRows.length - 1), + ), + ); + } + } + + @override + Widget build(BuildContext context) { + dataTableShowLogs = false; + final selectedId = ref.watch(selectedIdStateProvider); + final requestModel = ref.watch(selectedRequestModelProvider); + final mqttModel = requestModel?.protocolModel as MQTTRequestModel?; + + if (mqttModel == null) return kSizedBoxEmpty; + + final subTopics = mqttModel.subscribedTopics; + bool isTopicsEmpty = subTopics.isEmpty; + + topicRows = isTopicsEmpty + ? [kNameValueEmptyModel] + : subTopics + [kNameValueEmptyModel]; + + isRowEnabledList = [ + ...mqttModel.isTopicEnabledList, + ]; + if (isRowEnabledList.length < subTopics.length) { + isRowEnabledList.addAll(List.filled(subTopics.length - isRowEnabledList.length, true)); + } + isRowEnabledList.add(false); + isAddingRow = false; + + List columns = const [ + DataColumn2( + label: Text(kNameCheckbox), + fixedWidth: 30, + ), + DataColumn2( + label: Text("Topic"), + ), + DataColumn2( + label: Text(''), + fixedWidth: 32, + ), + ]; + + List dataRows = List.generate( + topicRows.length, + (index) { + bool isLast = index + 1 == topicRows.length; + return DataRow( + key: ValueKey("$selectedId-$index-mqtt-topics-row-$seed"), + cells: [ + DataCell( + ADCheckBox( + keyId: "$selectedId-$index-mqtt-topics-c-$seed", + value: isRowEnabledList[index], + onChanged: isLast + ? null + : (value) { + setState(() { + isRowEnabledList[index] = value!; + }); + _onFieldChange(); + + // Handle live subscription/unsubscription + if (requestModel?.isStreaming ?? false) { + if (value!) { + ref.read(collectionStateNotifierProvider.notifier).subscribeMqttTopic(selectedId!, topicRows[index].name, mqttModel.qos); + } else { + ref.read(collectionStateNotifierProvider.notifier).unsubscribeMqttTopic(selectedId!, topicRows[index].name); + } + } + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + EnvCellField( + keyId: "$selectedId-$index-mqtt-topics-k-$seed", + initialValue: topicRows[index].name, + hintText: "Add topic to subscribe...", + onChanged: (value) { + final oldTopic = topicRows[index].name; + topicRows[index] = topicRows[index].copyWith(name: value); + if (isLast && !isAddingRow) { + isAddingRow = true; + topicRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + } + _onFieldChange(); + + // Handle live subscription change + if ((requestModel?.isStreaming ?? false) && isRowEnabledList[index]) { + if (oldTopic.isNotEmpty) { + ref.read(collectionStateNotifierProvider.notifier).unsubscribeMqttTopic(selectedId!, oldTopic); + } + if (value.isNotEmpty) { + ref.read(collectionStateNotifierProvider.notifier).subscribeMqttTopic(selectedId!, value, mqttModel.qos); + } + } + }, + colorScheme: Theme.of(context).colorScheme, + ), + ), + DataCell( + InkWell( + onTap: isLast + ? null + : () { + seed = random.nextInt(kRandMax); + final topicToRemove = topicRows[index].name; + if (topicRows.length == 2) { + setState(() { + topicRows = [kNameValueEmptyModel]; + isRowEnabledList = [false]; + }); + } else { + topicRows.removeAt(index); + isRowEnabledList.removeAt(index); + } + _onFieldChange(); + + if ((requestModel?.isStreaming ?? false) && topicToRemove.isNotEmpty) { + ref.read(collectionStateNotifierProvider.notifier).unsubscribeMqttTopic(selectedId!, topicToRemove); + } + }, + child: Theme.of(context).brightness == Brightness.dark + ? kIconRemoveDark + : kIconRemoveLight, + ), + ), + ], + ); + }, + ); + + return Stack( + children: [ + Container( + margin: kPh10t10, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Theme( + data: Theme.of(context) + .copyWith(scrollbarTheme: kDataTableScrollbarTheme), + child: DataTable2( + columnSpacing: 12, + dividerThickness: 0, + horizontalMargin: 0, + headingRowHeight: 0, + dataRowHeight: kDataTableRowHeight, + bottomMargin: kDataTableBottomPadding, + isVerticalScrollBarVisible: true, + columns: columns, + rows: dataRows, + ), + ), + ), + if (!kIsMobile) kVSpacer40, + ], + ), + ), + if (!kIsMobile) + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: kPb15, + child: ElevatedButton.icon( + onPressed: () { + setState(() { + topicRows.add(kNameValueEmptyModel); + isRowEnabledList.add(false); + }); + _onFieldChange(); + }, + icon: const Icon(Icons.add), + label: const Text( + "Add Topic", + style: kTextStyleButton, + ), + ), + ), + ), + ], + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/response_pane.dart b/lib/screens/home_page/editor_pane/details_card/response_pane.dart index 0e701d5f99..a369fe4d67 100644 --- a/lib/screens/home_page/editor_pane/details_card/response_pane.dart +++ b/lib/screens/home_page/editor_pane/details_card/response_pane.dart @@ -4,15 +4,24 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/consts.dart'; +import 'package:apidash/models/protocols/websocket_model.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; +import 'event_stream_view.dart'; class ResponsePane extends ConsumerWidget { const ResponsePane({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { + final apiType = ref.watch( + selectedRequestModelProvider.select((value) => value?.apiType)); final isWorking = ref.watch( selectedRequestModelProvider.select((value) => value?.isWorking)) ?? false; + final isStreaming = ref.watch( + selectedRequestModelProvider.select((value) => value?.isStreaming)) ?? + false; final startSendingTime = ref.watch( selectedRequestModelProvider.select((value) => value?.sendingTime)); final responseStatus = ref.watch( @@ -20,6 +29,30 @@ class ResponsePane extends ConsumerWidget { final message = ref .watch(selectedRequestModelProvider.select((value) => value?.message)); + if (apiType == APIType.websocket || + apiType == APIType.mqtt || + apiType == APIType.grpc) { + if (isWorking) { + return SendingWidget(startSendingTime: startSendingTime); + } + + final protocolModel = ref.watch(selectedRequestModelProvider.select((value) => value?.protocolModel)); + bool hasMessages = false; + if (protocolModel is WebSocketRequestModel) { + hasMessages = protocolModel.messageHistory.isNotEmpty; + } else if (protocolModel is MQTTRequestModel) { + hasMessages = protocolModel.messageHistory.isNotEmpty; + } else if (protocolModel is GrpcRequestModel) { + hasMessages = protocolModel.messageHistory.isNotEmpty; + } + + if (isStreaming || hasMessages) { + return const _WsResponsePanel(); + } + + return const NotSentWidget(); + } + if (isWorking) { return SendingWidget( startSendingTime: startSendingTime, @@ -43,6 +76,48 @@ class ResponsePane extends ConsumerWidget { } } +class _WsResponsePanel extends ConsumerWidget { + const _WsResponsePanel(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return DefaultTabController( + length: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TabBar( + labelColor: Theme.of(context).colorScheme.primary, + unselectedLabelColor: Theme.of(context).colorScheme.onSurfaceVariant, + tabs: const [ + Tab(text: "Response Body"), + Tab(text: "Headers"), + ], + ), + const Expanded( + child: TabBarView( + children: [ + EventStreamView(), + _WsNoHeadersTab(), + ], + ), + ), + ], + ), + ); + } +} + +class _WsNoHeadersTab extends StatelessWidget { + const _WsNoHeadersTab(); + @override + Widget build(BuildContext context) { + return const Center( + child: Text("No response headers for WebSocket connection."), + ); + } +} + class ResponseDetails extends ConsumerWidget { const ResponseDetails({super.key}); diff --git a/lib/screens/home_page/editor_pane/url_card.dart b/lib/screens/home_page/editor_pane/url_card.dart index d84f27a7f4..eb6696f5a3 100644 --- a/lib/screens/home_page/editor_pane/url_card.dart +++ b/lib/screens/home_page/editor_pane/url_card.dart @@ -1,9 +1,14 @@ +import 'package:apidash/consts.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; +import 'package:apidash/models/protocols/websocket_model.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; + import '../../common_widgets/common_widgets.dart'; class EditorPaneRequestURLCard extends ConsumerWidget { @@ -36,6 +41,11 @@ class EditorPaneRequestURLCard extends ConsumerWidget { APIType.rest => const DropdownButtonHTTPMethod(), APIType.graphql => kSizedBoxEmpty, APIType.ai => const AIModelSelector(), + APIType.websocket || + APIType.mqtt || + APIType.grpc => + kSizedBoxEmpty, + null => kSizedBoxEmpty, }, switch (apiType) { @@ -53,6 +63,11 @@ class EditorPaneRequestURLCard extends ConsumerWidget { APIType.rest => const DropdownButtonHTTPMethod(), APIType.graphql => kSizedBoxEmpty, APIType.ai => const AIModelSelector(), + APIType.websocket || + APIType.mqtt || + APIType.grpc => + kSizedBoxEmpty, + null => kSizedBoxEmpty, }, switch (apiType) { @@ -102,24 +117,87 @@ class URLTextField extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selectedId = ref.watch(selectedIdStateProvider); + final apiType = ref.watch( + selectedRequestModelProvider.select((value) => value?.apiType)); ref.watch(selectedRequestModelProvider .select((value) => value?.aiRequestModel?.url)); ref.watch(selectedRequestModelProvider .select((value) => value?.httpRequestModel?.url)); + ref.watch(selectedRequestModelProvider + .select((value) => value?.protocolModel)); final requestModel = ref .read(collectionStateNotifierProvider.notifier) .getRequestModel(selectedId!)!; + + String? urlValue; + switch (requestModel.apiType) { + case APIType.ai: + urlValue = requestModel.aiRequestModel?.url; + break; + case APIType.websocket: + final pm = requestModel.protocolModel; + urlValue = pm is WebSocketRequestModel ? pm.url : null; + break; + case APIType.mqtt: + final pm = requestModel.protocolModel; + urlValue = pm is MQTTRequestModel ? pm.brokerUrl : null; + break; + case APIType.grpc: + final pm = requestModel.protocolModel; + if (pm is GrpcRequestModel) { + urlValue = pm.port == 50051 ? pm.host : '${pm.host}:${pm.port}'; + } + break; + default: + urlValue = requestModel.httpRequestModel?.url; + } + return EnvURLField( + // ValueKey encodes both the selected request and its protocol type. + // This forces Flutter to discard the old widget and create a fresh one + // whenever the user switches between requests or between protocol types, + // ensuring that `initialValue` is re-applied correctly instead of being + // stuck on the value from the previous protocol's form state. + key: ValueKey('${selectedId}_${apiType?.name}'), selectedId: selectedId, - initialValue: switch (requestModel.apiType) { - APIType.ai => requestModel.aiRequestModel?.url, - _ => requestModel.httpRequestModel?.url, + initialValue: urlValue, + hintText: switch (requestModel.apiType) { + APIType.websocket => kHintTextWsCard, + APIType.mqtt => kHintTextMqttCard, + APIType.grpc => kHintTextGrpcCard, + _ => kHintTextUrlCard, }, onChanged: (value) { if (requestModel.apiType == APIType.ai) { ref.read(collectionStateNotifierProvider.notifier).update( aiRequestModel: requestModel.aiRequestModel?.copyWith(url: value)); + } else if (requestModel.apiType == APIType.websocket) { + final protocolModel = requestModel.protocolModel; + if (protocolModel is WebSocketRequestModel) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: protocolModel.copyWith(url: value)); + } + } else if (requestModel.apiType == APIType.mqtt) { + final protocolModel = requestModel.protocolModel; + if (protocolModel is MQTTRequestModel) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: protocolModel.copyWith(brokerUrl: value)); + } + } else if (requestModel.apiType == APIType.grpc) { + String host = value.trim(); + int port = 50051; + if (host.contains(':')) { + final parts = host.split(':'); + host = parts[0].trim(); + final p = int.tryParse(parts[1].trim()); + if (p != null) port = p; + } + final protocolModel = requestModel.protocolModel; + if (protocolModel is GrpcRequestModel) { + ref.read(collectionStateNotifierProvider.notifier).update( + protocolModel: protocolModel.copyWith(host: host, port: port)); + } } else { ref.read(collectionStateNotifierProvider.notifier).update(url: value); } diff --git a/lib/services/connection_manager.dart b/lib/services/connection_manager.dart new file mode 100644 index 0000000000..56f4682f2f --- /dev/null +++ b/lib/services/connection_manager.dart @@ -0,0 +1,178 @@ +// lib/services/connection_manager.dart + +import 'package:flutter/foundation.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:web_socket_channel/io.dart'; +import 'package:mqtt_client/mqtt_client.dart'; +import 'package:mqtt_client/mqtt_server_client.dart'; +import 'package:grpc/grpc.dart'; +import 'package:apidash/models/protocols/websocket_model.dart'; +import 'package:apidash/models/protocols/mqtt_model.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; + +/// A singleton service that holds active connections. +/// It allows the UI or CLI to retrieve an existing connection or create a new one. +class ConnectionManager { + ConnectionManager._privateConstructor(); + static final ConnectionManager _instance = ConnectionManager._privateConstructor(); + static ConnectionManager get instance => _instance; + + // Maps request id to active connections. + final Map _webSocketChannels = {}; + final Map _mqttClients = {}; + final Map _grpcChannels = {}; + + // WebSocket + WebSocketChannel getWebSocketChannel(String requestId) => _webSocketChannels[requestId]!; + + Future connectWebSocket(String requestId, WebSocketRequestModel model) async { + final uri = Uri.parse(model.url); + final channel = IOWebSocketChannel.connect(uri, headers: model.customHeaders); + _webSocketChannels[requestId] = channel; + return channel; + } + + void disconnectWebSocket(String requestId) { + final channel = _webSocketChannels.remove(requestId); + channel?.sink.close(); + } + + // MQTT + MqttServerClient getMqttClient(String requestId) => _mqttClients[requestId]!; + + Future connectMqtt(String requestId, MQTTRequestModel model) async { + String host = model.brokerUrl; + if (host.contains("://")) { + try { + final uri = Uri.parse(host); + host = uri.host; + } catch (e) { + debugPrint("Error parsing MQTT URL: $e"); + } + } + + debugPrint("Connecting to MQTT broker: $host:${model.port} (TLS: ${model.useTLS})"); + + final client = MqttServerClient(host, model.clientId ?? 'apidash_$requestId'); + client.port = model.port; + client.useWebSocket = model.useWebSocket; + client.logging(on: true); // Temporarily enable logging to debug + client.keepAlivePeriod = 20; + client.secure = model.useTLS; + + // Set protocol version + if (model.version == MQTTVersion.v3) { + client.setProtocolV31(); + } else if (model.version == MQTTVersion.v3_1_1) { + client.setProtocolV311(); + } + // MqttServerClient by default supports v3.1.1 or v5 depending on version. + // For V5, usually we use MqttServerClient.withPort if needed or it defaults if supported. + + if (model.username != null && model.username!.isNotEmpty) { + client.connectionMessage = MqttConnectMessage() + .withClientIdentifier(client.clientIdentifier) + .authenticateAs(model.username!, model.password ?? ''); + } + + final status = await client.connect(); + if (status?.state != MqttConnectionState.connected) { + throw Exception("Connection failed: ${status?.state}"); + } + + _mqttClients[requestId] = client; + return client; + } + + void subscribeMqtt(String requestId, String topic, int qos) { + final client = _mqttClients[requestId]; + if (client != null && client.connectionStatus?.state == MqttConnectionState.connected) { + client.subscribe(topic, MqttQos.values[qos]); + } + } + + void unsubscribeMqtt(String requestId, String topic) { + final client = _mqttClients[requestId]; + if (client != null && client.connectionStatus?.state == MqttConnectionState.connected) { + client.unsubscribe(topic); + } + } + + void publishMqtt(String requestId, String topic, String message, int qos) { + final client = _mqttClients[requestId]; + if (client != null && client.connectionStatus?.state == MqttConnectionState.connected) { + final builder = MqttClientPayloadBuilder(); + builder.addString(message); + client.publishMessage(topic, MqttQos.values[qos], builder.payload!); + } + } + + void disconnectMqtt(String requestId) { + final client = _mqttClients.remove(requestId); + client?.disconnect(); + } + + // gRPC + ClientChannel getGrpcChannel(String requestId) => _grpcChannels[requestId]!; + + Future connectGrpc(String requestId, GrpcRequestModel model) async { + String host = model.host.trim(); + int port = model.port; + + if (host.contains(':')) { + final parts = host.split(':'); + host = parts[0].trim(); + final p = int.tryParse(parts[1].trim()); + if (p != null) port = p; + } + + print("gRPC Connecting to: $host:$port"); + final channel = ClientChannel( + host, + port: port, + options: ChannelOptions( + credentials: model.useTLS + ? const ChannelCredentials.secure() + : const ChannelCredentials.insecure(), + ), + ); + _grpcChannels[requestId] = channel; + print("gRPC Channel established for $requestId"); + return channel; + } + + void disconnectGrpc(String requestId) { + final channel = _grpcChannels.remove(requestId); + channel?.terminate(); + } + + Stream> callGrpcMethod( + String requestId, + String service, + String method, + List requestBytes, { + Map? metadata, + }) { + final channel = _grpcChannels[requestId]; + if (channel == null) { + throw Exception("No active gRPC channel for $requestId"); + } + + // Path is usually /{service}/{method} + final path = "/$service/$method"; + + final clientMethod = ClientMethod, List>( + path, + (List value) => value, + (List value) => value, + ); + + final call = channel.createCall( + clientMethod, + Stream.fromIterable([requestBytes]), + CallOptions(metadata: metadata), + ); + + return call.response; + } +} diff --git a/lib/services/grpc_reflection_service.dart b/lib/services/grpc_reflection_service.dart new file mode 100644 index 0000000000..19be9b6543 --- /dev/null +++ b/lib/services/grpc_reflection_service.dart @@ -0,0 +1,507 @@ +import 'package:protobuf/protobuf.dart'; +import 'package:apidash/models/protocols/grpc_model.dart'; +import 'package:apidash/services/connection_manager.dart'; + +class GrpcMethodSchema { + final String? inputType; + final String? outputType; + final DescriptorProto? inputDescriptor; + final DescriptorProto? outputDescriptor; + final Map allDescriptors; + + GrpcMethodSchema({ + this.inputType, + this.outputType, + this.inputDescriptor, + this.outputDescriptor, + required this.allDescriptors, + }); +} + +// Minimal Descriptor definitions to extract method names +class FileDescriptorProto extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('FileDescriptorProto', package: const PackageName('google.protobuf')) + ..aOS(1, 'name') + ..aOS(2, 'package') + ..pc(4, 'messageType', PbFieldType.PM, subBuilder: DescriptorProto.create) + ..pc(6, 'service', PbFieldType.PM, subBuilder: ServiceDescriptorProto.create) + ..hasRequiredFields = false; + + FileDescriptorProto() : super(); + factory FileDescriptorProto.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + static FileDescriptorProto create() => FileDescriptorProto._(); + FileDescriptorProto._() : super(); + @override + BuilderInfo get info_ => _i; + @override + FileDescriptorProto clone() => FileDescriptorProto()..mergeFromMessage(this); + @override + FileDescriptorProto createEmptyInstance() => create(); + + String get package => $_getS(1, ''); + List get service => $_getList(3); + List get messageType => $_getList(2); +} + +class ServiceDescriptorProto extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('ServiceDescriptorProto', package: const PackageName('google.protobuf')) + ..aOS(1, 'name') + ..pc(2, 'method', PbFieldType.PM, subBuilder: MethodDescriptorProto.create) + ..hasRequiredFields = false; + + ServiceDescriptorProto() : super(); + static ServiceDescriptorProto create() => ServiceDescriptorProto._(); + ServiceDescriptorProto._() : super(); + @override + BuilderInfo get info_ => _i; + @override + ServiceDescriptorProto clone() => ServiceDescriptorProto()..mergeFromMessage(this); + @override + ServiceDescriptorProto createEmptyInstance() => create(); + + String get name => $_getS(0, ''); + List get method => $_getList(1); +} + +class MethodDescriptorProto extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('MethodDescriptorProto', package: const PackageName('google.protobuf')) + ..aOS(1, 'name') + ..aOS(2, 'inputType') + ..aOS(3, 'outputType') + ..hasRequiredFields = false; + + MethodDescriptorProto() : super(); + static MethodDescriptorProto create() => MethodDescriptorProto._(); + MethodDescriptorProto._() : super(); + @override + BuilderInfo get info_ => _i; + @override + MethodDescriptorProto clone() => MethodDescriptorProto()..mergeFromMessage(this); + @override + MethodDescriptorProto createEmptyInstance() => create(); + + String get name => $_getS(0, ''); + String get inputType => $_getS(1, ''); + String get outputType => $_getS(2, ''); +} + +class DescriptorProto extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('DescriptorProto', package: const PackageName('google.protobuf')) + ..aOS(1, 'name') + ..pc(2, 'field', PbFieldType.PM, subBuilder: FieldDescriptorProto.create) + ..hasRequiredFields = false; + + DescriptorProto() : super(); + static DescriptorProto create() => DescriptorProto._(); + DescriptorProto._() : super(); + @override + BuilderInfo get info_ => _i; + @override + DescriptorProto clone() => DescriptorProto()..mergeFromMessage(this); + @override + DescriptorProto createEmptyInstance() => create(); + + String get name => $_getS(0, ''); + List get field => $_getList(1); +} + +class FieldDescriptorProto extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('FieldDescriptorProto', package: const PackageName('google.protobuf')) + ..aOS(1, 'name') + ..a(3, 'number', PbFieldType.O3) + ..e(4, 'label', PbFieldType.OE, defaultOrMaker: FieldDescriptorProto_Label.LABEL_OPTIONAL, valueOf: FieldDescriptorProto_Label.valueOf, enumValues: FieldDescriptorProto_Label.values) + ..e(5, 'type', PbFieldType.OE, defaultOrMaker: FieldDescriptorProto_Type.TYPE_DOUBLE, valueOf: FieldDescriptorProto_Type.valueOf, enumValues: FieldDescriptorProto_Type.values) + ..aOS(6, 'typeName') + ..hasRequiredFields = false; + + FieldDescriptorProto() : super(); + static FieldDescriptorProto create() => FieldDescriptorProto._(); + FieldDescriptorProto._() : super(); + @override + BuilderInfo get info_ => _i; + @override + FieldDescriptorProto clone() => FieldDescriptorProto()..mergeFromMessage(this); + @override + FieldDescriptorProto createEmptyInstance() => create(); + + String get name => $_getS(0, ''); + int get number => $_getIZ(1); + String get typeName => $_getS(4, ''); + FieldDescriptorProto_Type get type => $_getN(3); +} + +class FieldDescriptorProto_Type extends ProtobufEnum { + static const FieldDescriptorProto_Type TYPE_DOUBLE = FieldDescriptorProto_Type._(1, 'TYPE_DOUBLE'); + static const FieldDescriptorProto_Type TYPE_FLOAT = FieldDescriptorProto_Type._(2, 'TYPE_FLOAT'); + static const FieldDescriptorProto_Type TYPE_INT64 = FieldDescriptorProto_Type._(3, 'TYPE_INT64'); + static const FieldDescriptorProto_Type TYPE_UINT64 = FieldDescriptorProto_Type._(4, 'TYPE_UINT64'); + static const FieldDescriptorProto_Type TYPE_INT32 = FieldDescriptorProto_Type._(5, 'TYPE_INT32'); + static const FieldDescriptorProto_Type TYPE_FIXED64 = FieldDescriptorProto_Type._(6, 'TYPE_FIXED64'); + static const FieldDescriptorProto_Type TYPE_FIXED32 = FieldDescriptorProto_Type._(7, 'TYPE_FIXED32'); + static const FieldDescriptorProto_Type TYPE_BOOL = FieldDescriptorProto_Type._(8, 'TYPE_BOOL'); + static const FieldDescriptorProto_Type TYPE_STRING = FieldDescriptorProto_Type._(9, 'TYPE_STRING'); + static const FieldDescriptorProto_Type TYPE_GROUP = FieldDescriptorProto_Type._(10, 'TYPE_GROUP'); + static const FieldDescriptorProto_Type TYPE_MESSAGE = FieldDescriptorProto_Type._(11, 'TYPE_MESSAGE'); + static const FieldDescriptorProto_Type TYPE_BYTES = FieldDescriptorProto_Type._(12, 'TYPE_BYTES'); + static const FieldDescriptorProto_Type TYPE_UINT32 = FieldDescriptorProto_Type._(13, 'TYPE_UINT32'); + static const FieldDescriptorProto_Type TYPE_ENUM = FieldDescriptorProto_Type._(14, 'TYPE_ENUM'); + static const FieldDescriptorProto_Type TYPE_SFIXED32 = FieldDescriptorProto_Type._(15, 'TYPE_SFIXED32'); + static const FieldDescriptorProto_Type TYPE_SFIXED64 = FieldDescriptorProto_Type._(16, 'TYPE_SFIXED64'); + static const FieldDescriptorProto_Type TYPE_SINT32 = FieldDescriptorProto_Type._(17, 'TYPE_SINT32'); + static const FieldDescriptorProto_Type TYPE_SINT64 = FieldDescriptorProto_Type._(18, 'TYPE_SINT64'); + + static const List values = [ + TYPE_DOUBLE, TYPE_FLOAT, TYPE_INT64, TYPE_UINT64, TYPE_INT32, TYPE_FIXED64, TYPE_FIXED32, TYPE_BOOL, TYPE_STRING, TYPE_GROUP, TYPE_MESSAGE, TYPE_BYTES, TYPE_UINT32, TYPE_ENUM, TYPE_SFIXED32, TYPE_SFIXED64, TYPE_SINT32, TYPE_SINT64, + ]; + + static final Map _byValue = ProtobufEnum.initByValue(values); + static FieldDescriptorProto_Type? valueOf(int value) => _byValue[value]; + + const FieldDescriptorProto_Type._(int v, String n) : super(v, n); +} + +class FieldDescriptorProto_Label extends ProtobufEnum { + static const FieldDescriptorProto_Label LABEL_OPTIONAL = FieldDescriptorProto_Label._(1, 'LABEL_OPTIONAL'); + static const FieldDescriptorProto_Label LABEL_REQUIRED = FieldDescriptorProto_Label._(2, 'LABEL_REQUIRED'); + static const FieldDescriptorProto_Label LABEL_REPEATED = FieldDescriptorProto_Label._(3, 'LABEL_REPEATED'); + + static const List values = [ + LABEL_OPTIONAL, LABEL_REQUIRED, LABEL_REPEATED, + ]; + + static final Map _byValue = ProtobufEnum.initByValue(values); + static FieldDescriptorProto_Label? valueOf(int value) => _byValue[value]; + + const FieldDescriptorProto_Label._(int v, String n) : super(v, n); +} + +class ServerReflectionRequest extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('ServerReflectionRequest', + package: const PackageName('grpc.reflection.v1alpha'), + createEmptyInstance: create) + ..aOS(1, 'host') + ..aOS(3, 'fileByFilename') + ..aOS(4, 'fileBySymbol') + ..aOS(7, 'listServices') + ..hasRequiredFields = false; + + ServerReflectionRequest() : super(); + factory ServerReflectionRequest.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + static ServerReflectionRequest create() => ServerReflectionRequest._(); + ServerReflectionRequest._() : super(); + + @override + BuilderInfo get info_ => _i; + @override + ServerReflectionRequest clone() => ServerReflectionRequest()..mergeFromMessage(this); + @override + ServerReflectionRequest createEmptyInstance() => create(); + + String get host => $_getS(0, ''); + set host(String v) => $_setString(0, v); + + String get fileByFilename => $_getS(1, ''); + set fileByFilename(String v) => $_setString(1, v); + + String get fileBySymbol => $_getS(2, ''); + set fileBySymbol(String v) => $_setString(2, v); + + String get listServices => $_getS(3, ''); + set listServices(String v) => $_setString(3, v); +} + +class ListServiceResponse extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('ListServiceResponse', + package: const PackageName('grpc.reflection.v1alpha'), + createEmptyInstance: create) + ..pc(1, 'service', PbFieldType.PM, subBuilder: ServiceResponse.create) + ..hasRequiredFields = false; + + ListServiceResponse() : super(); + static ListServiceResponse create() => ListServiceResponse._(); + ListServiceResponse._() : super(); + + @override + BuilderInfo get info_ => _i; + @override + ListServiceResponse clone() => ListServiceResponse()..mergeFromMessage(this); + @override + ListServiceResponse createEmptyInstance() => create(); + + List get service => $_getList(0); +} + +class ServiceResponse extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('ServiceResponse', + package: const PackageName('grpc.reflection.v1alpha'), + createEmptyInstance: create) + ..aOS(1, 'name') + ..hasRequiredFields = false; + + ServiceResponse() : super(); + factory ServiceResponse.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + static ServiceResponse create() => ServiceResponse._(); + ServiceResponse._() : super(); + + @override + BuilderInfo get info_ => _i; + @override + ServiceResponse clone() => ServiceResponse()..mergeFromMessage(this); + @override + ServiceResponse createEmptyInstance() => create(); + + String get name => $_getS(0, ''); +} + +class FileDescriptorResponse extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('FileDescriptorResponse', + package: const PackageName('grpc.reflection.v1alpha'), + createEmptyInstance: create) + ..p>(1, 'fileDescriptorProto', PbFieldType.PY) + ..hasRequiredFields = false; + + FileDescriptorResponse() : super(); + static FileDescriptorResponse create() => FileDescriptorResponse._(); + FileDescriptorResponse._() : super(); + + @override + BuilderInfo get info_ => _i; + @override + FileDescriptorResponse clone() => FileDescriptorResponse()..mergeFromMessage(this); + @override + FileDescriptorResponse createEmptyInstance() => create(); + + List> get fileDescriptorProto => $_getList(0); +} + +class ServerReflectionResponse extends GeneratedMessage { + static final BuilderInfo _i = BuilderInfo('ServerReflectionResponse', + package: const PackageName('grpc.reflection.v1alpha'), + createEmptyInstance: create) + ..aOS(1, 'validHost') + ..aOM(2, 'originalRequest', subBuilder: ServerReflectionRequest.create) + ..aOM(4, 'fileDescriptorResponse', subBuilder: FileDescriptorResponse.create) + ..aOM(6, 'listServicesResponse', subBuilder: ListServiceResponse.create) + ..hasRequiredFields = false; + + ServerReflectionResponse() : super(); + factory ServerReflectionResponse.fromBuffer(List i, + [ExtensionRegistry r = ExtensionRegistry.EMPTY]) => + create()..mergeFromBuffer(i, r); + static ServerReflectionResponse create() => ServerReflectionResponse._(); + ServerReflectionResponse._() : super(); + + @override + BuilderInfo get info_ => _i; + @override + ServerReflectionResponse clone() => ServerReflectionResponse()..mergeFromMessage(this); + @override + ServerReflectionResponse createEmptyInstance() => create(); + + ListServiceResponse get listServicesResponse => $_getN(3); + FileDescriptorResponse get fileDescriptorResponse => $_getN(2); +} + +class GrpcReflectionService { + static Future> listServices(String requestId, GrpcRequestModel model) async { + final request = ServerReflectionRequest()..host = model.host..listServices = ""; + + try { + final call = ConnectionManager.instance.callGrpcMethod( + requestId, + "grpc.reflection.v1alpha.ServerReflection", + "ServerReflectionInfo", + request.writeToBuffer(), + ); + + final services = []; + await for (final responseBytes in call) { + final response = ServerReflectionResponse.fromBuffer(responseBytes); + if (response.hasField(6)) { + for (final service in response.listServicesResponse.service) { + services.add(service.name); + } + break; + } + } + return services; + } catch (e) { + return []; + } + } + + static Future>> getMethodsForService(String requestId, GrpcRequestModel model, String serviceName) async { + final request = ServerReflectionRequest()..host = model.host..fileBySymbol = serviceName; + + try { + final call = ConnectionManager.instance.callGrpcMethod( + requestId, + "grpc.reflection.v1alpha.ServerReflection", + "ServerReflectionInfo", + request.writeToBuffer(), + ); + + final Map> result = {}; + + await for (final responseBytes in call) { + final response = ServerReflectionResponse.fromBuffer(responseBytes); + if (response.hasField(4)) { + for (final protoBytes in response.fileDescriptorResponse.fileDescriptorProto) { + final fileProto = FileDescriptorProto.fromBuffer(protoBytes); + final package = fileProto.package; + + for (final service in fileProto.service) { + final fullName = package.isNotEmpty ? "$package.${service.name}" : service.name; + if (fullName == serviceName) { + final methods = service.method.map((m) => m.name).toList(); + result[fullName] = methods; + } + } + } + if (result.isNotEmpty) break; + } + } + return result; + } catch (e) { + return {}; + } + } + + static Future getMethodSchema(String requestId, GrpcRequestModel model, String serviceName, String methodName) async { + final request = ServerReflectionRequest()..host = model.host..fileBySymbol = serviceName; + + try { + final call = ConnectionManager.instance.callGrpcMethod( + requestId, + "grpc.reflection.v1alpha.ServerReflection", + "ServerReflectionInfo", + request.writeToBuffer(), + ); + + String? inputType; + String? outputType; + final List fileProtos = []; + + await for (final responseBytes in call) { + final response = ServerReflectionResponse.fromBuffer(responseBytes); + if (response.hasField(4)) { + for (final protoBytes in response.fileDescriptorResponse.fileDescriptorProto) { + final fileProto = FileDescriptorProto.fromBuffer(protoBytes); + fileProtos.add(fileProto); + final package = fileProto.package; + + for (final service in fileProto.service) { + final fullName = package.isNotEmpty ? "$package.${service.name}" : service.name; + if (fullName == serviceName) { + for (final method in service.method) { + if (method.name == methodName) { + inputType = method.inputType; + outputType = method.outputType; + if (inputType.startsWith('.')) inputType = inputType.substring(1); + if (outputType.startsWith('.')) outputType = outputType.substring(1); + break; + } + } + } + } + } + if (inputType != null && outputType != null) break; + } + } + + if (inputType == null || outputType == null) return null; + + final allDescriptors = {}; + for (final fp in fileProtos) { + final package = fp.package; + for (final msg in fp.messageType) { + final fullName = package.isNotEmpty ? "$package.${msg.name}" : msg.name; + allDescriptors[fullName] = msg; + } + } + + for (final type in [inputType, outputType]) { + if (!allDescriptors.containsKey(type)) { + final requestMsg = ServerReflectionRequest()..host = model.host..fileBySymbol = type; + final callMsg = ConnectionManager.instance.callGrpcMethod( + requestId, + "grpc.reflection.v1alpha.ServerReflection", + "ServerReflectionInfo", + requestMsg.writeToBuffer(), + ); + + await for (final responseBytes in callMsg) { + final response = ServerReflectionResponse.fromBuffer(responseBytes); + if (response.hasField(4)) { + for (final protoBytes in response.fileDescriptorResponse.fileDescriptorProto) { + final fileProto = FileDescriptorProto.fromBuffer(protoBytes); + final package = fileProto.package; + for (final msg in fileProto.messageType) { + final fullName = package.isNotEmpty ? "$package.${msg.name}" : msg.name; + allDescriptors[fullName] = msg; + } + } + } + } + } + } + + return GrpcMethodSchema( + inputType: inputType, + outputType: outputType, + inputDescriptor: allDescriptors[inputType], + outputDescriptor: allDescriptors[outputType], + allDescriptors: allDescriptors, + ); + + } catch (e) { + print("Error in getMethodSchema: $e"); + return null; + } + } + + static Future> getParamsForMethod(String requestId, GrpcRequestModel model, String serviceName, String methodName) async { + try { + final schema = await getMethodSchema(requestId, model, serviceName, methodName); + if (schema == null || schema.inputDescriptor == null) return []; + + return schema.inputDescriptor!.field.map((f) => GrpcParameterModel( + name: f.name, + tag: f.number, + type: _mapTypeToString(f.type), + enabled: true, + value: "", + )).toList(); + } catch (e) { + print("Error in getParamsForMethod: $e"); + return []; + } + } + + static String _mapTypeToString(FieldDescriptorProto_Type type) { + if (type == FieldDescriptorProto_Type.TYPE_DOUBLE) return 'double'; + if (type == FieldDescriptorProto_Type.TYPE_FLOAT) return 'float'; + if (type == FieldDescriptorProto_Type.TYPE_INT64) return 'int64'; + if (type == FieldDescriptorProto_Type.TYPE_UINT64) return 'uint64'; + if (type == FieldDescriptorProto_Type.TYPE_INT32) return 'int32'; + if (type == FieldDescriptorProto_Type.TYPE_FIXED64) return 'int64'; + if (type == FieldDescriptorProto_Type.TYPE_FIXED32) return 'int32'; + if (type == FieldDescriptorProto_Type.TYPE_BOOL) return 'bool'; + if (type == FieldDescriptorProto_Type.TYPE_STRING) return 'string'; + if (type == FieldDescriptorProto_Type.TYPE_MESSAGE) return 'message'; + if (type == FieldDescriptorProto_Type.TYPE_BYTES) return 'bytes'; + if (type == FieldDescriptorProto_Type.TYPE_UINT32) return 'uint32'; + if (type == FieldDescriptorProto_Type.TYPE_ENUM) return 'enum'; + if (type == FieldDescriptorProto_Type.TYPE_SFIXED32) return 'int32'; + if (type == FieldDescriptorProto_Type.TYPE_SFIXED64) return 'int64'; + if (type == FieldDescriptorProto_Type.TYPE_SINT32) return 'int32'; + if (type == FieldDescriptorProto_Type.TYPE_SINT64) return 'int64'; + return 'string'; + } +} diff --git a/lib/utils/grpc_utils.dart b/lib/utils/grpc_utils.dart new file mode 100644 index 0000000000..2d4afada64 --- /dev/null +++ b/lib/utils/grpc_utils.dart @@ -0,0 +1,295 @@ +import 'dart:io'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:apidash/models/protocols/grpc_model.dart'; +import 'package:apidash/services/grpc_reflection_service.dart'; + +class GrpcUtils { + static Future> parseProtoFile(String path) async { + try { + final file = File(path); + if (!await file.exists()) return {}; + + final content = await file.readAsString(); + final services = []; + final methods = >{}; + final messageFields = >{}; + + // Basic regex for services + final serviceRegex = RegExp(r'service\s+(\w+)\s*\{'); + final matches = serviceRegex.allMatches(content); + + for (final match in matches) { + final serviceName = match.group(1)!; + services.add(serviceName); + + // Find methods for this service + // This is a simplified search and won't handle complex nesting well + final serviceBlockRegex = RegExp('service\\s+$serviceName\\s*\\{([^\\}]*)\\}'); + final serviceBlock = serviceBlockRegex.firstMatch(content)?.group(1) ?? ""; + + final methodRegex = RegExp(r'rpc\s+(\w+)\s*\(([^)]*)\)\s+returns\s*\(([^)]*)\)'); + final methodMatches = methodRegex.allMatches(serviceBlock); + + final serviceMethods = []; + for (final mMatch in methodMatches) { + final methodName = mMatch.group(1)!; + final requestType = mMatch.group(2)!.trim(); + serviceMethods.add(methodName); + + // Store request type to map to fields later + methods["$serviceName/$methodName"] = [requestType]; + } + methods[serviceName] = serviceMethods; + } + + // Basic regex for messages (to populate form fields) + final messageRegex = RegExp(r'message\s+(\w+)\s*\{([^\}]*)\}'); + final msgMatches = messageRegex.allMatches(content); + + for (final match in msgMatches) { + final msgName = match.group(1)!; + final msgBody = match.group(2)!; + + final fields = []; + final fieldLineRegex = RegExp(r'(\w+)\s+(\w+)\s*=\s*(\d+);'); + final fieldLines = fieldLineRegex.allMatches(msgBody); + + for (final fMatch in fieldLines) { + final type = fMatch.group(1)!; + final name = fMatch.group(2)!; + final tag = int.tryParse(fMatch.group(3)!) ?? 0; + + fields.add(GrpcParameterModel( + name: name, + tag: tag, + type: type, + enabled: true, + value: "", + )); + } + messageFields[msgName] = fields; + } + + return { + 'services': services, + 'methods': methods, + 'messageFields': messageFields, + }; + } catch (e) { + print("Error parsing proto: $e"); + return {}; + } + } + + static String decodeBinaryResponse(List data, {GrpcMethodSchema? schema}) { + try { + if (data.isEmpty) return ""; + + final mapped = _decodeWithSchema(data, schema?.outputDescriptor, schema?.allDescriptors ?? {}); + return _prettyJson(mapped); + } catch (e) { + return data.toString(); + } + } + + static Map _decodeWithSchema(List data, dynamic descriptor, Map allDescriptors) { + final result = {}; + int offset = 0; + + while (offset < data.length) { + final key = _readVarint(data, offset); + if (key == null) break; + offset = key.nextOffset; + + final tag = key.value >> 3; + final wireType = key.value & 0x07; + + dynamic fieldDesc; + if (descriptor != null) { + for (final f in descriptor.field) { + if (f.number == tag) { + fieldDesc = f; + break; + } + } + } + + final fieldName = fieldDesc != null ? fieldDesc.name : tag.toString(); + + switch (wireType) { + case 0: // Varint + final val = _readVarint(data, offset); + if (val == null) return result; + result[fieldName] = val.value; + offset = val.nextOffset; + break; + case 2: // Length-delimited + final len = _readVarint(data, offset); + if (len == null) return result; + offset = len.nextOffset; + final bytes = data.sublist(offset, offset + len.value); + offset += len.value; + + if (fieldDesc != null && fieldDesc.type.toString() == 'TYPE_MESSAGE') { + var typeName = fieldDesc.typeName; + if (typeName.startsWith('.')) typeName = typeName.substring(1); + final nestedDesc = allDescriptors[typeName]; + result[fieldName] = _decodeWithSchema(bytes, nestedDesc, allDescriptors); + } else { + try { + result[fieldName] = utf8.decode(bytes); + } catch (_) { + // If there's no descriptor, fallback to checking if it's likely protobuf + if (descriptor == null && _isLikelyProtobuf(bytes)) { + try { + result[fieldName] = _decodeWithSchema(bytes, null, allDescriptors); + } catch (_) { + result[fieldName] = bytes.toString(); + } + } else { + result[fieldName] = bytes.toString(); + } + } + } + break; + case 1: // 64-bit + offset += 8; + break; + case 5: // 32-bit + offset += 4; + break; + default: + return result; + } + } + return result; + } + + static bool _isLikelyProtobuf(List data) { + if (data.isEmpty) return false; + final firstByte = data[0]; + final wireType = firstByte & 0x07; + return wireType <= 5; + } + + static _VarintResult? _readVarint(List data, int offset) { + int value = 0; + int shift = 0; + int index = offset; + + while (index < data.length) { + final b = data[index++]; + value |= (b & 0x7F) << shift; + if (b < 0x80) return _VarintResult(value, index); + shift += 7; + if (shift >= 64) break; + } + return null; + } + + static String paramsToJson(List params) { + if (params.isEmpty) return ""; + final map = {}; + for (var p in params) { + if (p.enabled && p.name.isNotEmpty) { + dynamic val = p.value; + if (p.type == 'int32' || p.type == 'uint32' || p.type == 'sint32' || p.type == 'fixed32' || p.type == 'sfixed32') { + val = int.tryParse(p.value) ?? 0; + } else if (p.type == 'int64' || p.type == 'uint64' || p.type == 'sint64' || p.type == 'fixed64' || p.type == 'sfixed64') { + val = int.tryParse(p.value) ?? 0; + } else if (p.type == 'double' || p.type == 'float') { + val = double.tryParse(p.value) ?? 0.0; + } else if (p.type == 'bool') { + val = p.value.toLowerCase() == 'true'; + } + map[p.name] = val; + } + } + return _prettyJson(map); + } + + static List paramsToBytes(List params) { + if (params.isEmpty) return []; + + final List result = []; + for (var p in params) { + if (!p.enabled || p.name.isEmpty || p.tag == null) continue; + + final tag = p.tag!; + final wireType = _getWireType(p.type); + + // Write tag & wire type + _writeVarint(result, (tag << 3) | wireType); + + switch (wireType) { + case 0: // Varint + int val = 0; + if (p.type == 'bool') { + val = p.value.toLowerCase() == 'true' ? 1 : 0; + } else { + val = int.tryParse(p.value) ?? 0; + } + _writeVarint(result, val); + break; + case 2: // Length-delimited + final bytes = utf8.encode(p.value); + _writeVarint(result, bytes.length); + result.addAll(bytes); + break; + case 1: // 64-bit + // Simple fixed64/double (simplified) + final val = double.tryParse(p.value) ?? 0.0; + final bdata = ByteData(8); + bdata.setFloat64(0, val, Endian.little); + result.addAll(bdata.buffer.asUint8List()); + break; + case 5: // 32-bit + final val = double.tryParse(p.value) ?? 0.0; + final bdata = ByteData(4); + bdata.setFloat32(0, val.toDouble(), Endian.little); + result.addAll(bdata.buffer.asUint8List()); + break; + } + } + return result; + } + + static int _getWireType(String type) { + switch (type) { + case 'double': + case 'fixed64': + case 'sfixed64': + return 1; + case 'float': + case 'fixed32': + case 'sfixed32': + return 5; + case 'string': + case 'bytes': + case 'message': + return 2; + default: + return 0; // Varint for most ints and bool + } + } + + static void _writeVarint(List buffer, int value) { + while (value >= 0x80) { + buffer.add((value & 0x7F) | 0x80); + value >>= 7; + } + buffer.add(value); + } + + static String _prettyJson(dynamic obj) { + const encoder = JsonEncoder.withIndent(' '); + return encoder.convert(obj); + } +} + +class _VarintResult { + final int value; + final int nextOffset; + _VarintResult(this.value, this.nextOffset); +} diff --git a/lib/utils/ui_utils.dart b/lib/utils/ui_utils.dart index 52b5fcc988..e88f865e77 100644 --- a/lib/utils/ui_utils.dart +++ b/lib/utils/ui_utils.dart @@ -37,6 +37,9 @@ Color getAPIColor( ), APIType.graphql => kColorGQL, APIType.ai => Colors.amber, + APIType.websocket => Colors.teal, + APIType.mqtt => Colors.indigo, + APIType.grpc => Colors.deepOrange, }; if (brightness == Brightness.dark) { col = col.toDark; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index bca76b79d0..e851112fc2 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -10,3 +10,4 @@ export 'save_utils.dart'; export 'ui_utils.dart'; export 'validation_utils.dart'; export 'window_utils.dart'; +export 'grpc_utils.dart'; diff --git a/lib/widgets/field_url.dart b/lib/widgets/field_url.dart index 01dd1db42a..d228848153 100644 --- a/lib/widgets/field_url.dart +++ b/lib/widgets/field_url.dart @@ -9,12 +9,14 @@ class URLField extends StatelessWidget { this.initialValue, this.onChanged, this.onFieldSubmitted, + this.hintText, }); final String selectedId; final String? initialValue; final void Function(String)? onChanged; final void Function(String)? onFieldSubmitted; + final String? hintText; @override Widget build(BuildContext context) { @@ -23,7 +25,7 @@ class URLField extends StatelessWidget { initialValue: initialValue, style: kCodeStyle, decoration: InputDecoration( - hintText: kHintTextUrlCard, + hintText: hintText ?? kHintTextUrlCard, hintStyle: kCodeStyle.copyWith( color: Theme.of(context).colorScheme.outlineVariant, ), diff --git a/lib/widgets/texts.dart b/lib/widgets/texts.dart index 9d2e1a8457..0f6266b7fe 100644 --- a/lib/widgets/texts.dart +++ b/lib/widgets/texts.dart @@ -21,6 +21,9 @@ class SidebarRequestCardTextBox extends StatelessWidget { APIType.rest => method!.abbr, APIType.graphql => apiType.abbr, APIType.ai => apiType.abbr, + APIType.websocket => apiType.abbr, + APIType.mqtt => apiType.abbr, + APIType.grpc => apiType.abbr, }, textAlign: TextAlign.center, style: TextStyle( diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 002cc2e7fe..7c3c6c1bef 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -3,7 +3,11 @@ import 'dart:convert'; enum APIType { rest("HTTP", "HTTP"), ai("AI", "AI"), - graphql("GraphQL", "GQL"); + graphql("GraphQL", "GQL"), + websocket("WebSocket", "WS"), + mqtt("MQTT", "MQTT"), + grpc("gRPC", "gRPC"), + ; const APIType(this.label, this.abbr); final String label; diff --git a/packages/better_networking/lib/utils/http_request_utils.dart b/packages/better_networking/lib/utils/http_request_utils.dart index 6540395a54..e3a23be7a6 100644 --- a/packages/better_networking/lib/utils/http_request_utils.dart +++ b/packages/better_networking/lib/utils/http_request_utils.dart @@ -94,6 +94,9 @@ String? getRequestBody(APIType type, HttpRequestModel httpRequestModel) { : null, APIType.graphql => getGraphQLBody(httpRequestModel), APIType.ai => null, //TODO: TAKE A LOOK + APIType.websocket => null, + APIType.mqtt => null, + APIType.grpc => null, }; } diff --git a/pubspec.lock b/pubspec.lock index fd5c199097..daae96f52e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -433,6 +433,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.7" + event_bus: + dependency: transitive + description: + name: event_bus + sha256: "1a55e97923769c286d295240048fc180e7b0768902c3c2e869fe059aafa15304" + url: "https://pub.dev" + source: hosted + version: "2.0.1" extended_text_field: dependency: "direct main" description: @@ -762,6 +770,22 @@ packages: url: "https://pub.dev" source: hosted version: "8.0.2" + google_identity_services_web: + dependency: transitive + description: + name: google_identity_services_web + sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" + url: "https://pub.dev" + source: hosted + version: "0.3.3+1" + googleapis_auth: + dependency: transitive + description: + name: googleapis_auth + sha256: b81fe352cc4a330b3710d2b7ad258d9bcef6f909bb759b306bf42973a7d046db + url: "https://pub.dev" + source: hosted + version: "2.0.0" graphs: dependency: transitive description: @@ -770,6 +794,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + grpc: + dependency: "direct main" + description: + name: grpc + sha256: "15227eeed339bd0ef5afe515cb791b2e4bec0711ab56f37cc44257bcfaedc4bf" + url: "https://pub.dev" + source: hosted + version: "4.2.0" highlight: dependency: "direct main" description: @@ -850,6 +882,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.6.0" + http2: + dependency: transitive + description: + name: http2 + sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa" + url: "https://pub.dev" + source: hosted + version: "2.3.1" http_multi_server: dependency: transitive description: @@ -1143,6 +1183,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + mqtt_client: + dependency: "direct main" + description: + name: mqtt_client + sha256: fde192a91f1d71b540574490f7f7e35302298f1342a4daf350c0ddc15e9d01f2 + url: "https://pub.dev" + source: hosted + version: "10.11.10" multi_split_view: dependency: "direct main" description: @@ -1407,6 +1455,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + protobuf: + dependency: "direct main" + description: + name: protobuf + sha256: de9c9eb2c33f8e933a42932fe1dc504800ca45ebc3d673e6ed7f39754ee4053e + url: "https://pub.dev" + source: hosted + version: "4.2.0" provider: dependency: "direct main" description: @@ -2109,7 +2165,7 @@ packages: source: hosted version: "1.0.1" web_socket_channel: - dependency: transitive + dependency: "direct main" description: name: web_socket_channel sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 diff --git a/pubspec.yaml b/pubspec.yaml index 4a4ceb87d2..ef7beaabdc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -74,6 +74,10 @@ dependencies: git: url: https://github.com/google/flutter-desktop-embedding.git path: plugins/window_size + web_socket_channel: ^3.0.3 + mqtt_client: ^10.11.10 + grpc: ^4.1.2 + protobuf: ^4.1.0 dependency_overrides: extended_text_field: ^16.0.0