✨ 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.
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
include: package:flutter_lints/flutter.yaml
|
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:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
@ -43,7 +43,7 @@ PODS:
|
|||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_native_splash (0.0.1):
|
- flutter_native_splash (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_secure_storage (3.3.1):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -119,7 +119,7 @@ SPEC CHECKSUMS:
|
|||||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||||
|
@ -11,6 +11,7 @@ import 'package:surface/providers/sn_attachment.dart';
|
|||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/theme.dart';
|
import 'package:surface/providers/theme.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
|
import 'package:surface/providers/websocket.dart';
|
||||||
import 'package:surface/router.dart';
|
import 'package:surface/router.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
@ -39,11 +40,15 @@ class SolianApp extends StatelessWidget {
|
|||||||
assetLoader: JsonAssetLoader(),
|
assetLoader: JsonAssetLoader(),
|
||||||
child: MultiProvider(
|
child: MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
// Display layer
|
||||||
|
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
||||||
|
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
||||||
|
|
||||||
|
// Data layer
|
||||||
Provider(create: (_) => SnNetworkProvider()),
|
Provider(create: (_) => SnNetworkProvider()),
|
||||||
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
||||||
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
|
||||||
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
ChangeNotifierProvider(create: (ctx) => UserProvider(ctx)),
|
||||||
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
ChangeNotifierProvider(create: (ctx) => WebSocketProvider(ctx)),
|
||||||
],
|
],
|
||||||
child: AppMainContent(),
|
child: AppMainContent(),
|
||||||
),
|
),
|
||||||
@ -63,7 +68,7 @@ class AppMainContent extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
context.read<NavigationProvider>();
|
context.read<NavigationProvider>();
|
||||||
context.read<UserProvider>();
|
context.read<WebSocketProvider>();
|
||||||
|
|
||||||
final th = context.watch<ThemeProvider>();
|
final th = context.watch<ThemeProvider>();
|
||||||
|
|
||||||
|
@ -44,48 +44,11 @@ class SnNetworkProvider {
|
|||||||
RequestOptions options,
|
RequestOptions options,
|
||||||
RequestInterceptorHandler handler,
|
RequestInterceptorHandler handler,
|
||||||
) async {
|
) async {
|
||||||
try {
|
final atk = await getFreshAtk();
|
||||||
var atk = await _storage.read(key: kAtkStoreKey);
|
if (atk != null) {
|
||||||
if (atk != null) {
|
options.headers['Authorization'] = 'Bearer $atk';
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
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) {
|
String getAttachmentUrl(String ky) {
|
||||||
if (ky.startsWith("http")) return ky;
|
if (ky.startsWith("http")) return ky;
|
||||||
return '${client.options.baseUrl}/cgi/uc/attachments/$ky';
|
return '${client.options.baseUrl}/cgi/uc/attachments/$ky';
|
||||||
|
@ -13,6 +13,8 @@ class UserProvider extends ChangeNotifier {
|
|||||||
late final SnNetworkProvider _sn;
|
late final SnNetworkProvider _sn;
|
||||||
late final FlutterSecureStorage _storage = FlutterSecureStorage();
|
late final FlutterSecureStorage _storage = FlutterSecureStorage();
|
||||||
|
|
||||||
|
Future<String?> get atk => _storage.read(key: kAtkStoreKey);
|
||||||
|
|
||||||
UserProvider(BuildContext context) {
|
UserProvider(BuildContext context) {
|
||||||
_sn = context.read<SnNetworkProvider>();
|
_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
|
source: hosted
|
||||||
version: "0.1.6"
|
version: "0.1.6"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||||
|
@ -73,6 +73,7 @@ dependencies:
|
|||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
collection: ^1.18.0
|
collection: ^1.18.0
|
||||||
mime: ^2.0.0
|
mime: ^2.0.0
|
||||||
|
web_socket_channel: ^3.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user