✨ Basic websocket connection
This commit is contained in:
parent
2e68d227a0
commit
8bc0da5188
@ -9,6 +9,13 @@
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- "**/*.g.dart"
|
||||
- "**/*.freezed.dart"
|
||||
errors:
|
||||
invalid_annotation_target: ignore # Due to freezed + json_serializable issue, ref https://github.com/rrousselGit/freezed/issues/488#issuecomment-894358980
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
|
@ -43,7 +43,7 @@ PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- flutter_secure_storage (6.0.0):
|
||||
- Flutter
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
@ -119,7 +119,7 @@ SPEC CHECKSUMS:
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||
|
@ -11,6 +11,7 @@ import 'package:surface/providers/sn_attachment.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/providers/theme.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/providers/websocket.dart';
|
||||
import 'package:surface/router.dart';
|
||||
|
||||
void main() async {
|
||||
@ -39,11 +40,15 @@ class SolianApp extends StatelessWidget {
|
||||
assetLoader: JsonAssetLoader(),
|
||||
child: MultiProvider(
|
||||
providers: [
|
||||
// Display layer
|
||||
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
||||
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
||||
|
||||
// Data layer
|
||||
Provider(create: (_) => SnNetworkProvider()),
|
||||
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
||||
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
||||
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
||||
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
||||
],
|
||||
child: AppMainContent(),
|
||||
),
|
||||
@ -63,7 +68,7 @@ class AppMainContent extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
context.read<NavigationProvider>();
|
||||
context.read<UserProvider>();
|
||||
context.read<WebSocketProvider>();
|
||||
|
||||
final th = context.watch<ThemeProvider>();
|
||||
|
||||
|
@ -44,48 +44,11 @@ class SnNetworkProvider {
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) async {
|
||||
try {
|
||||
var atk = await _storage.read(key: kAtkStoreKey);
|
||||
if (atk != null) {
|
||||
final atkParts = atk.split('.');
|
||||
if (atkParts.length != 3) {
|
||||
throw Exception('invalid format of access token');
|
||||
}
|
||||
|
||||
var rawPayload =
|
||||
atkParts[1].replaceAll('-', '+').replaceAll('_', '/');
|
||||
switch (rawPayload.length % 4) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
rawPayload += '==';
|
||||
break;
|
||||
case 3:
|
||||
rawPayload += '=';
|
||||
break;
|
||||
default:
|
||||
throw Exception('illegal format of access token payload');
|
||||
}
|
||||
|
||||
final b64 = utf8.fuse(base64Url);
|
||||
final payload = b64.decode(rawPayload);
|
||||
final exp = jsonDecode(payload)['exp'];
|
||||
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
||||
log('Access token need refresh, doing it at ${DateTime.now()}');
|
||||
atk = await refreshToken();
|
||||
}
|
||||
|
||||
if (atk != null) {
|
||||
options.headers['Authorization'] = 'Bearer $atk';
|
||||
} else {
|
||||
log('Access token refresh failed...');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log('Failed to authenticate user: $err');
|
||||
} finally {
|
||||
handler.next(options);
|
||||
final atk = await getFreshAtk();
|
||||
if (atk != null) {
|
||||
options.headers['Authorization'] = 'Bearer $atk';
|
||||
}
|
||||
return handler.next(options);
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -99,6 +62,50 @@ class SnNetworkProvider {
|
||||
});
|
||||
}
|
||||
|
||||
Future<String?> getFreshAtk() async {
|
||||
try {
|
||||
var atk = await _storage.read(key: kAtkStoreKey);
|
||||
if (atk != null) {
|
||||
final atkParts = atk.split('.');
|
||||
if (atkParts.length != 3) {
|
||||
throw Exception('invalid format of access token');
|
||||
}
|
||||
|
||||
var rawPayload = atkParts[1].replaceAll('-', '+').replaceAll('_', '/');
|
||||
switch (rawPayload.length % 4) {
|
||||
case 0:
|
||||
break;
|
||||
case 2:
|
||||
rawPayload += '==';
|
||||
break;
|
||||
case 3:
|
||||
rawPayload += '=';
|
||||
break;
|
||||
default:
|
||||
throw Exception('illegal format of access token payload');
|
||||
}
|
||||
|
||||
final b64 = utf8.fuse(base64Url);
|
||||
final payload = b64.decode(rawPayload);
|
||||
final exp = jsonDecode(payload)['exp'];
|
||||
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
||||
log('Access token need refresh, doing it at ${DateTime.now()}');
|
||||
atk = await refreshToken();
|
||||
}
|
||||
|
||||
if (atk != null) {
|
||||
return atk;
|
||||
} else {
|
||||
log('Access token refresh failed...');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
log('Failed to authenticate user: $err');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String getAttachmentUrl(String ky) {
|
||||
if (ky.startsWith("http")) return ky;
|
||||
return '${client.options.baseUrl}/cgi/uc/attachments/$ky';
|
||||
|
@ -13,6 +13,8 @@ class UserProvider extends ChangeNotifier {
|
||||
late final SnNetworkProvider _sn;
|
||||
late final FlutterSecureStorage _storage = FlutterSecureStorage();
|
||||
|
||||
Future<String?> get atk => _storage.read(key: kAtkStoreKey);
|
||||
|
||||
UserProvider(BuildContext context) {
|
||||
_sn = context.read<SnNetworkProvider>();
|
||||
|
||||
|
109
lib/providers/websocket.dart
Normal file
109
lib/providers/websocket.dart
Normal file
@ -0,0 +1,109 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/types/websocket.dart';
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
|
||||
class WebSocketProvider extends ChangeNotifier {
|
||||
bool isBusy = false;
|
||||
bool isConnected = false;
|
||||
|
||||
WebSocketChannel? conn;
|
||||
|
||||
late final SnNetworkProvider _sn;
|
||||
late final UserProvider _ua;
|
||||
|
||||
StreamController<WebSocketPackage> stream = StreamController.broadcast();
|
||||
|
||||
WebSocketProvider(BuildContext context) {
|
||||
_sn = context.read<SnNetworkProvider>();
|
||||
_ua = context.read<UserProvider>();
|
||||
|
||||
// Wait for the userinfo provide initialize authorization status
|
||||
Future.delayed(const Duration(milliseconds: 250), () async {
|
||||
if (_ua.isAuthorized) {
|
||||
log('[WebSocket] Connecting to the server...');
|
||||
await connect();
|
||||
} else {
|
||||
log('[WebSocket] Unable connect to the server, unauthorized.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> connect({noRetry = false}) async {
|
||||
if (!_ua.isAuthorized) return;
|
||||
if (isConnected) {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
final atk = await _sn.getFreshAtk();
|
||||
final uri = Uri.parse(
|
||||
'${_sn.client.options.baseUrl.replaceFirst('http', 'ws')}/ws?tk=$atk',
|
||||
);
|
||||
|
||||
isBusy = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
conn = WebSocketChannel.connect(uri);
|
||||
await conn!.ready;
|
||||
log('[WebSocket] Connected to server!');
|
||||
} catch (err) {
|
||||
if (err is WebSocketChannelException) {
|
||||
log('Failed to connect to websocket: ${(err.inner as dynamic).message}');
|
||||
} else {
|
||||
log('Failed to connect to websocket: $err');
|
||||
}
|
||||
|
||||
if (!noRetry) {
|
||||
log('Retry connecting to websocket in 3 seconds...');
|
||||
return Future.delayed(
|
||||
const Duration(seconds: 3),
|
||||
() => connect(noRetry: true),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
isBusy = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void disconnect() {
|
||||
if (conn != null) {
|
||||
conn!.sink.close();
|
||||
}
|
||||
isConnected = false;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void listen() {
|
||||
conn?.stream.listen(
|
||||
(event) {
|
||||
final packet = WebSocketPackage.fromJson(jsonDecode(event));
|
||||
log('Websocket incoming message: ${packet.method} ${packet.message}');
|
||||
stream.sink.add(packet);
|
||||
// TODO handle notification
|
||||
// if (packet.method == 'notifications.new') {
|
||||
// final NotificationProvider nty = Get.find();
|
||||
// nty.notifications.add(Notification.fromJson(packet.payload!));
|
||||
// nty.notificationUnread.value++;
|
||||
// }
|
||||
},
|
||||
onDone: () {
|
||||
isConnected = false;
|
||||
notifyListeners();
|
||||
Future.delayed(const Duration(seconds: 1), () => connect());
|
||||
},
|
||||
onError: (err) {
|
||||
isConnected = false;
|
||||
notifyListeners();
|
||||
Future.delayed(const Duration(seconds: 11), () => connect());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
17
lib/types/websocket.dart
Normal file
17
lib/types/websocket.dart
Normal file
@ -0,0 +1,17 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'websocket.freezed.dart';
|
||||
part 'websocket.g.dart';
|
||||
|
||||
@freezed
|
||||
class WebSocketPackage with _$WebSocketPackage {
|
||||
const factory WebSocketPackage({
|
||||
@JsonKey(name: 'w') @Default('unknown') String method,
|
||||
@JsonKey(name: 'e') String? endpoint,
|
||||
@JsonKey(name: 'm') String? message,
|
||||
@JsonKey(name: 'p') @Default({}) Map<String, dynamic>? payload,
|
||||
}) = _WebSocketPackage;
|
||||
|
||||
factory WebSocketPackage.fromJson(Map<String, dynamic> json) =>
|
||||
_$WebSocketPackageFromJson(json);
|
||||
}
|
252
lib/types/websocket.freezed.dart
Normal file
252
lib/types/websocket.freezed.dart
Normal file
@ -0,0 +1,252 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// 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.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(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');
|
||||
|
||||
WebSocketPackage _$WebSocketPackageFromJson(Map<String, dynamic> json) {
|
||||
return _WebSocketPackage.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$WebSocketPackage {
|
||||
@JsonKey(name: 'w')
|
||||
String get method => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'e')
|
||||
String? get endpoint => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'm')
|
||||
String? get message => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: 'p')
|
||||
Map<String, dynamic>? get payload => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this WebSocketPackage to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of WebSocketPackage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$WebSocketPackageCopyWith<WebSocketPackage> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $WebSocketPackageCopyWith<$Res> {
|
||||
factory $WebSocketPackageCopyWith(
|
||||
WebSocketPackage value, $Res Function(WebSocketPackage) then) =
|
||||
_$WebSocketPackageCopyWithImpl<$Res, WebSocketPackage>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'w') String method,
|
||||
@JsonKey(name: 'e') String? endpoint,
|
||||
@JsonKey(name: 'm') String? message,
|
||||
@JsonKey(name: 'p') Map<String, dynamic>? payload});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$WebSocketPackageCopyWithImpl<$Res, $Val extends WebSocketPackage>
|
||||
implements $WebSocketPackageCopyWith<$Res> {
|
||||
_$WebSocketPackageCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of WebSocketPackage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? method = null,
|
||||
Object? endpoint = freezed,
|
||||
Object? message = freezed,
|
||||
Object? payload = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
method: null == method
|
||||
? _value.method
|
||||
: method // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endpoint: freezed == endpoint
|
||||
? _value.endpoint
|
||||
: endpoint // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
message: freezed == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
payload: freezed == payload
|
||||
? _value.payload
|
||||
: payload // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$WebSocketPackageImplCopyWith<$Res>
|
||||
implements $WebSocketPackageCopyWith<$Res> {
|
||||
factory _$$WebSocketPackageImplCopyWith(_$WebSocketPackageImpl value,
|
||||
$Res Function(_$WebSocketPackageImpl) then) =
|
||||
__$$WebSocketPackageImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'w') String method,
|
||||
@JsonKey(name: 'e') String? endpoint,
|
||||
@JsonKey(name: 'm') String? message,
|
||||
@JsonKey(name: 'p') Map<String, dynamic>? payload});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$WebSocketPackageImplCopyWithImpl<$Res>
|
||||
extends _$WebSocketPackageCopyWithImpl<$Res, _$WebSocketPackageImpl>
|
||||
implements _$$WebSocketPackageImplCopyWith<$Res> {
|
||||
__$$WebSocketPackageImplCopyWithImpl(_$WebSocketPackageImpl _value,
|
||||
$Res Function(_$WebSocketPackageImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of WebSocketPackage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? method = null,
|
||||
Object? endpoint = freezed,
|
||||
Object? message = freezed,
|
||||
Object? payload = freezed,
|
||||
}) {
|
||||
return _then(_$WebSocketPackageImpl(
|
||||
method: null == method
|
||||
? _value.method
|
||||
: method // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endpoint: freezed == endpoint
|
||||
? _value.endpoint
|
||||
: endpoint // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
message: freezed == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
payload: freezed == payload
|
||||
? _value._payload
|
||||
: payload // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$WebSocketPackageImpl implements _WebSocketPackage {
|
||||
const _$WebSocketPackageImpl(
|
||||
{@JsonKey(name: 'w') this.method = 'unknown',
|
||||
@JsonKey(name: 'e') this.endpoint,
|
||||
@JsonKey(name: 'm') this.message,
|
||||
@JsonKey(name: 'p') final Map<String, dynamic>? payload = const {}})
|
||||
: _payload = payload;
|
||||
|
||||
factory _$WebSocketPackageImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$WebSocketPackageImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'w')
|
||||
final String method;
|
||||
@override
|
||||
@JsonKey(name: 'e')
|
||||
final String? endpoint;
|
||||
@override
|
||||
@JsonKey(name: 'm')
|
||||
final String? message;
|
||||
final Map<String, dynamic>? _payload;
|
||||
@override
|
||||
@JsonKey(name: 'p')
|
||||
Map<String, dynamic>? get payload {
|
||||
final value = _payload;
|
||||
if (value == null) return null;
|
||||
if (_payload is EqualUnmodifiableMapView) return _payload;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WebSocketPackage(method: $method, endpoint: $endpoint, message: $message, payload: $payload)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$WebSocketPackageImpl &&
|
||||
(identical(other.method, method) || other.method == method) &&
|
||||
(identical(other.endpoint, endpoint) ||
|
||||
other.endpoint == endpoint) &&
|
||||
(identical(other.message, message) || other.message == message) &&
|
||||
const DeepCollectionEquality().equals(other._payload, _payload));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, method, endpoint, message,
|
||||
const DeepCollectionEquality().hash(_payload));
|
||||
|
||||
/// Create a copy of WebSocketPackage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$WebSocketPackageImplCopyWith<_$WebSocketPackageImpl> get copyWith =>
|
||||
__$$WebSocketPackageImplCopyWithImpl<_$WebSocketPackageImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$WebSocketPackageImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _WebSocketPackage implements WebSocketPackage {
|
||||
const factory _WebSocketPackage(
|
||||
{@JsonKey(name: 'w') final String method,
|
||||
@JsonKey(name: 'e') final String? endpoint,
|
||||
@JsonKey(name: 'm') final String? message,
|
||||
@JsonKey(name: 'p') final Map<String, dynamic>? payload}) =
|
||||
_$WebSocketPackageImpl;
|
||||
|
||||
factory _WebSocketPackage.fromJson(Map<String, dynamic> json) =
|
||||
_$WebSocketPackageImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'w')
|
||||
String get method;
|
||||
@override
|
||||
@JsonKey(name: 'e')
|
||||
String? get endpoint;
|
||||
@override
|
||||
@JsonKey(name: 'm')
|
||||
String? get message;
|
||||
@override
|
||||
@JsonKey(name: 'p')
|
||||
Map<String, dynamic>? get payload;
|
||||
|
||||
/// Create a copy of WebSocketPackage
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$WebSocketPackageImplCopyWith<_$WebSocketPackageImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
25
lib/types/websocket.g.dart
Normal file
25
lib/types/websocket.g.dart
Normal file
@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'websocket.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$WebSocketPackageImpl _$$WebSocketPackageImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$WebSocketPackageImpl(
|
||||
method: json['w'] as String? ?? 'unknown',
|
||||
endpoint: json['e'] as String?,
|
||||
message: json['m'] as String?,
|
||||
payload: json['p'] as Map<String, dynamic>? ?? const {},
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$WebSocketPackageImplToJson(
|
||||
_$WebSocketPackageImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'w': instance.method,
|
||||
'e': instance.endpoint,
|
||||
'm': instance.message,
|
||||
'p': instance.payload,
|
||||
};
|
@ -1480,7 +1480,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
|
@ -73,6 +73,7 @@ dependencies:
|
||||
path_provider: ^2.1.5
|
||||
collection: ^1.18.0
|
||||
mime: ^2.0.0
|
||||
web_socket_channel: ^3.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user