浏览代码

feat: connect to websocket and display messages

Fela Maslen 4 年之前
父节点
当前提交
502c3b5d29
共有 6 个文件被更改,包括 133 次插入7 次删除
  1. 2 0
      gmus-mobile/.env.example
  2. 6 0
      gmus-mobile/lib/config.dart
  3. 30 1
      gmus-mobile/lib/main.dart
  4. 54 0
      gmus-mobile/lib/socket.dart
  5. 35 0
      gmus-mobile/pubspec.lock
  6. 6 6
      gmus-mobile/pubspec.yaml

+ 2 - 0
gmus-mobile/.env.example

@@ -0,0 +1,2 @@
+DART_ENV=development
+API_URL=https://10.0.2.2:3003

+ 6 - 0
gmus-mobile/lib/config.dart

@@ -0,0 +1,6 @@
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+
+final config = {
+  'isDevelopment': env['DART_ENV'] == 'development',
+  'apiUrl': env['API_URL'] ?? 'http://localhost:3000',
+};

+ 30 - 1
gmus-mobile/lib/main.dart

@@ -1,7 +1,11 @@
+import 'dart:io';
+
+import 'package:flutter_dotenv/flutter_dotenv.dart' as DotEnv;
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 
-void main() => runApp(GetMaterialApp(home: Gmus()));
+import 'config.dart';
+import 'socket.dart' as socket;
 
 class Controller extends GetxController {
   var name = ''.obs;
@@ -30,9 +34,34 @@ class Gmus extends StatelessWidget {
                         hintText: 'Set name',
                       ),
                 ),
+                TextButton(
+                    child: Text('Connect'),
+                    onPressed: () {
+                      socket.connect(controller.name.value);
+                    },
+                ),
               ],
           ),
         ),
       );
   }
 }
+
+class MyHttpOverrides extends HttpOverrides {
+  @override
+  HttpClient createHttpClient(SecurityContext context) {
+    return super.createHttpClient(context)
+        ..badCertificateCallback =
+          (X509Certificate cert, String host, int port) => true;
+  }
+}
+
+Future<void> main() async {
+  await DotEnv.load(fileName: '.env');
+
+  if (config['isDevelopment']) {
+    HttpOverrides.global = new MyHttpOverrides();
+  }
+
+  runApp(GetMaterialApp(home: Gmus()));
+}

+ 54 - 0
gmus-mobile/lib/socket.dart

@@ -0,0 +1,54 @@
+import 'dart:convert';
+
+import 'package:nanoid/nanoid.dart';
+import 'package:web_socket_channel/io.dart';
+import 'package:web_socket_channel/web_socket_channel.dart';
+import 'package:web_socket_channel/status.dart' as status;
+
+import 'config.dart';
+
+String getApiUrlWithProtocol() {
+  final String baseUrl = config['apiUrl'];
+  if (baseUrl.startsWith('//')) {
+    return "https://$baseUrl";
+  }
+  return baseUrl;
+}
+
+String getWebSocketUrl() {
+  String apiUrlWithProtocol = getApiUrlWithProtocol();
+  String protocol = apiUrlWithProtocol.substring(0, apiUrlWithProtocol.indexOf('//'));
+  String apiUrlWithoutProtocol = apiUrlWithProtocol.substring(apiUrlWithProtocol.indexOf('//') + 2);
+
+  return "${(protocol == 'https:') ? 'wss' : 'ws'}://$apiUrlWithoutProtocol/pubsub";
+}
+
+String getUniqueName(String name) {
+  return "$name-${nanoid(5)}";
+}
+
+const socketKeepaliveTimeoutMs = 20000;
+
+Future keepalive(IOWebSocketChannel channel) {
+  return new Future.delayed(const Duration(milliseconds: socketKeepaliveTimeoutMs), () {
+    channel.sink.add(jsonEncode({'type': 'PING'}));
+
+    keepalive(channel);
+  });
+}
+
+void connect(String name) async {
+  final String uniqueName = getUniqueName(name);
+  final String webSocketUrl = getWebSocketUrl();
+  final String pubsubUrl = "$webSocketUrl?client-name=$uniqueName";
+
+  print("Connecting to socket: $pubsubUrl");
+
+  var channel = IOWebSocketChannel.connect(Uri.parse(pubsubUrl));
+
+  channel.stream.listen((message) {
+    print("Received message: $message");
+  });
+
+  keepalive(channel);
+}

+ 35 - 0
gmus-mobile/pubspec.lock

@@ -43,6 +43,20 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.15.0"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.1"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.1.5"
   cupertino_icons:
     dependency: "direct main"
     description:
@@ -62,6 +76,13 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_dotenv:
+    dependency: "direct main"
+    description:
+      name: flutter_dotenv
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "3.1.0"
   flutter_test:
     dependency: "direct dev"
     description: flutter
@@ -88,6 +109,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.3.0"
+  nanoid:
+    dependency: "direct main"
+    description:
+      name: nanoid
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.1.0"
   path:
     dependency: transitive
     description:
@@ -156,5 +184,12 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.1.0"
+  web_socket_channel:
+    dependency: "direct main"
+    description:
+      name: web_socket_channel
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.2.0"
 sdks:
   dart: ">=2.12.0-0.0 <3.0.0"

+ 6 - 6
gmus-mobile/pubspec.yaml

@@ -23,12 +23,11 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
-
-  get: ^3.25.4
-
-  # The following adds the Cupertino Icons font to your application.
-  # Use with the CupertinoIcons class for iOS style icons.
+  flutter_dotenv:
+  get:
   cupertino_icons: ^1.0.0
+  nanoid:
+  web_socket_channel:
 
 dev_dependencies:
   flutter_test:
@@ -46,7 +45,8 @@ flutter:
   uses-material-design: true
 
   # To add assets to your application, add an assets section, like this:
-  # assets:
+  assets:
+    - .env
   #   - images/a_dot_burr.jpeg
   #   - images/a_dot_ham.jpeg