Merge branch 'GetStream:develop' into fix-web-attachments

This commit is contained in:
Dawid
2021-11-10 17:38:09 +01:00
committed by GitHub
19 changed files with 119 additions and 37 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
flutter-version: ${{ env.flutter_version }} flutter-version: ${{ env.flutter_version }}
- name: "Install Tools" - name: "Install Tools"
run: flutter pub global activate melos 1.0.0-dev.3 run: flutter pub global activate melos 1.0.0-dev.6
- name: "Bootstrap Workspace" - name: "Bootstrap Workspace"
run: melos bootstrap run: melos bootstrap
@@ -31,7 +31,7 @@ jobs:
flutter-version: ${{ env.flutter_version }} flutter-version: ${{ env.flutter_version }}
- name: "Install Tools" - name: "Install Tools"
run: | run: |
flutter pub global activate melos 1.0.0-dev.3 flutter pub global activate melos 1.0.0-dev.6
- name: "Bootstrap Workspace" - name: "Bootstrap Workspace"
run: melos bootstrap run: melos bootstrap
- name: "Dart Analyze" - name: "Dart Analyze"
@@ -44,10 +44,6 @@ final _levelEmojiMapper = {
Level.SEVERE: '🚨', Level.SEVERE: '🚨',
}; };
final _userAgent = 'stream-chat-dart-client-'
'${CurrentPlatform.name}-'
'${PACKAGE_VERSION.split('+')[0]}';
/// The official Dart client for Stream Chat, /// The official Dart client for Stream Chat,
/// a service for building chat applications. /// a service for building chat applications.
/// This library can be used on any Dart project and on both mobile and web apps /// This library can be used on any Dart project and on both mobile and web apps
@@ -86,7 +82,7 @@ class StreamChatClient {
location: location, location: location,
connectTimeout: connectTimeout, connectTimeout: connectTimeout,
receiveTimeout: receiveTimeout, receiveTimeout: receiveTimeout,
headers: {'X-Stream-Client': _userAgent}, headers: {'X-Stream-Client': defaultUserAgent},
); );
_chatApi = chatApi ?? _chatApi = chatApi ??
@@ -106,7 +102,7 @@ class StreamChatClient {
tokenManager: _tokenManager, tokenManager: _tokenManager,
handler: handleEvent, handler: handleEvent,
logger: detachedLogger('🔌'), logger: detachedLogger('🔌'),
queryParameters: {'X-Stream-Client': _userAgent}, queryParameters: {'X-Stream-Client': defaultUserAgent},
); );
_retryPolicy = retryPolicy ?? _retryPolicy = retryPolicy ??
@@ -131,6 +127,14 @@ class StreamChatClient {
_originalChatPersistenceClient = value; _originalChatPersistenceClient = value;
} }
/// Default user agent for all requests
static String defaultUserAgent = 'stream-chat-dart-client-'
'${CurrentPlatform.name}-'
'${PACKAGE_VERSION.split('+')[0]}';
/// Additionals headers for all requests
static Map<String, Object?> additionalHeaders = {};
ChatPersistenceClient? _originalChatPersistenceClient; ChatPersistenceClient? _originalChatPersistenceClient;
/// Chat persistence client /// Chat persistence client
@@ -0,0 +1,17 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/stream_chat.dart';
/// Interceptor that sets additional headers for all requests.
class AdditionalHeadersInterceptor extends Interceptor {
@override
Future<void> onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
options.headers = {
...options.headers,
...StreamChatClient.additionalHeaders,
};
return handler.next(options);
}
}
@@ -5,6 +5,7 @@ import 'package:logging/logging.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:stream_chat/src/core/error/error.dart'; import 'package:stream_chat/src/core/error/error.dart';
import 'package:stream_chat/src/core/http/connection_id_manager.dart'; import 'package:stream_chat/src/core/http/connection_id_manager.dart';
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
@@ -41,6 +42,7 @@ class StreamHttpClient {
..._options.headers, ..._options.headers,
} }
..interceptors.addAll([ ..interceptors.addAll([
AdditionalHeadersInterceptor(),
if (tokenManager != null) AuthInterceptor(this, tokenManager), if (tokenManager != null) AuthInterceptor(this, tokenManager),
if (connectionIdManager != null) if (connectionIdManager != null)
ConnectionIdInterceptor(connectionIdManager), ConnectionIdInterceptor(connectionIdManager),
@@ -118,9 +118,9 @@ void main() {
setUpAll(() { setUpAll(() {
// Fallback values // Fallback values
registerFallbackValue<Message>(FakeMessage()); registerFallbackValue(FakeMessage());
registerFallbackValue<List<Message>>(<Message>[]); registerFallbackValue(<Message>[]);
registerFallbackValue<AttachmentFile>(FakeAttachmentFile()); registerFallbackValue(FakeAttachmentFile());
// detached loggers // detached loggers
when(() => client.detachedLogger(any())).thenAnswer((invocation) { when(() => client.detachedLogger(any())).thenAnswer((invocation) {
@@ -176,9 +176,9 @@ void main() {
setUpAll(() { setUpAll(() {
// Fallback values // Fallback values
registerFallbackValue<Message>(FakeMessage()); registerFallbackValue(FakeMessage());
registerFallbackValue<AttachmentFile>(FakeAttachmentFile()); registerFallbackValue(FakeAttachmentFile());
registerFallbackValue<Event>(FakeEvent()); registerFallbackValue(FakeEvent());
// detached loggers // detached loggers
when(() => client.detachedLogger(any())).thenAnswer((invocation) { when(() => client.detachedLogger(any())).thenAnswer((invocation) {
@@ -31,7 +31,7 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<User>(FakeUser()); registerFallbackValue(FakeUser());
}); });
setUp(() { setUp(() {
@@ -230,7 +230,7 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<User>(FakeUser()); registerFallbackValue(FakeUser());
}); });
setUp(() { setUp(() {
@@ -311,7 +311,7 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<User>(FakeUser()); registerFallbackValue(FakeUser());
}); });
setUp(() { setUp(() {
@@ -399,7 +399,7 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<User>(FakeUser()); registerFallbackValue(FakeUser());
}); });
setUp(() { setUp(() {
@@ -523,9 +523,9 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<Event>(FakeEvent()); registerFallbackValue(FakeEvent());
registerFallbackValue<PaginationParams>(const PaginationParams()); registerFallbackValue(const PaginationParams());
registerFallbackValue<ChannelState>(FakeChannelState()); registerFallbackValue(FakeChannelState());
}); });
setUp(() async { setUp(() async {
@@ -827,9 +827,9 @@ void main() {
setUpAll(() { setUpAll(() {
// fallback values // fallback values
registerFallbackValue<Event>(FakeEvent()); registerFallbackValue(FakeEvent());
registerFallbackValue<Message>(FakeMessage()); registerFallbackValue(FakeMessage());
registerFallbackValue<PaginationParams>(const PaginationParams()); registerFallbackValue(const PaginationParams());
}); });
setUp(() async { setUp(() async {
@@ -15,7 +15,7 @@ void main() {
setUp(() { setUp(() {
fileUploader = StreamAttachmentFileUploader(client); fileUploader = StreamAttachmentFileUploader(client);
registerFallbackValue<MultipartFile>(FakeMultiPartFile()); registerFallbackValue(FakeMultiPartFile());
}); });
Response successResponse(String path, {Object? data}) => Response( Response successResponse(String path, {Object? data}) => Response(
@@ -0,0 +1,29 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
import 'package:stream_chat/stream_chat.dart';
import 'package:test/test.dart';
void main() {
late AdditionalHeadersInterceptor additionalHeadersInterceptor;
setUp(() {
additionalHeadersInterceptor = AdditionalHeadersInterceptor();
});
test(
'`onRequest` should add additional headers in the request',
() async {
final options = RequestOptions(path: 'test-path');
final handler = RequestInterceptorHandler();
StreamChatClient.additionalHeaders = {'test-header': 'test-value'};
additionalHeadersInterceptor.onRequest(options, handler);
final updatedOptions = (await handler.future).data as RequestOptions;
final updateHeaders = updatedOptions.headers;
expect(updateHeaders.containsKey('test-header'), isTrue);
expect(updateHeaders['test-header'], 'test-value');
},
);
}
@@ -4,6 +4,7 @@ import 'package:mocktail/mocktail.dart';
import 'package:stream_chat/src/core/api/responses.dart'; import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/error/error.dart'; import 'package:stream_chat/src/core/error/error.dart';
import 'package:stream_chat/src/core/http/connection_id_manager.dart'; import 'package:stream_chat/src/core/http/connection_id_manager.dart';
import 'package:stream_chat/src/core/http/interceptor/additional_headers_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart'; import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
@@ -48,12 +49,23 @@ void main() {
return dioError; return dioError;
} }
test('UserAgentInterceptor should be added', () {
const apiKey = 'api-key';
final client = StreamHttpClient(apiKey);
expect(
client.httpClient.interceptors
.whereType<AdditionalHeadersInterceptor>()
.length,
1);
});
test('AuthInterceptor should be added if tokenManager is provided', () { test('AuthInterceptor should be added if tokenManager is provided', () {
const apiKey = 'api-key'; const apiKey = 'api-key';
final client = StreamHttpClient(apiKey, tokenManager: TokenManager()); final client = StreamHttpClient(apiKey, tokenManager: TokenManager());
expect(client.httpClient.interceptors.length, 1); expect(
expect(client.httpClient.interceptors.first, isA<AuthInterceptor>()); client.httpClient.interceptors.whereType<AuthInterceptor>().length, 1);
}); });
test( test(
@@ -65,10 +77,11 @@ void main() {
connectionIdManager: ConnectionIdManager(), connectionIdManager: ConnectionIdManager(),
); );
expect(client.httpClient.interceptors.length, 1);
expect( expect(
client.httpClient.interceptors.first, client.httpClient.interceptors
isA<ConnectionIdInterceptor>(), .whereType<ConnectionIdInterceptor>()
.length,
1,
); );
}, },
); );
@@ -80,10 +93,9 @@ void main() {
logger: Logger('test-logger'), logger: Logger('test-logger'),
); );
expect(client.httpClient.interceptors.length, 1);
expect( expect(
client.httpClient.interceptors.first, client.httpClient.interceptors.whereType<LoggingInterceptor>().length,
isA<LoggingInterceptor>(), 1,
); );
}); });
@@ -110,7 +110,15 @@ class StreamChatState extends State<StreamChat> {
onBackgroundEventReceived: widget.onBackgroundEventReceived, onBackgroundEventReceived: widget.onBackgroundEventReceived,
backgroundKeepAlive: widget.backgroundKeepAlive, backgroundKeepAlive: widget.backgroundKeepAlive,
connectivityStream: widget.connectivityStream, connectivityStream: widget.connectivityStream,
child: widget.child ?? const Offstage(), child: Builder(
builder: (context) {
StreamChatClient.additionalHeaders = {
'X-Stream-Client':
'${StreamChatClient.defaultUserAgent}-ui',
};
return widget.child ?? const Offstage();
},
),
), ),
); );
}, },
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'dart:ui'; import 'dart:ui';
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -120,7 +120,7 @@ class HomeScreen extends StatelessWidget {
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final _item = channels[index]; final _item = channels[index];
return ListTile( return ListTile(
title: Text(_item.name!), title: Text(_item.name ?? ''),
subtitle: StreamBuilder<Message?>( subtitle: StreamBuilder<Message?>(
stream: _item.state!.lastMessageStream, stream: _item.state!.lastMessageStream,
initialData: _item.state!.lastMessage, initialData: _item.state!.lastMessage,
@@ -95,7 +95,12 @@ class StreamChatCoreState extends State<StreamChatCore>
Timer? _disconnectTimer; Timer? _disconnectTimer;
@override @override
Widget build(BuildContext context) => widget.child; Widget build(BuildContext context) {
StreamChatClient.additionalHeaders = {
'X-Stream-Client': '${StreamChatClient.defaultUserAgent}-core',
};
return widget.child;
}
// coverage:ignore-start // coverage:ignore-start
@@ -10,7 +10,7 @@ import 'mocks.dart';
void main() { void main() {
setUpAll(() { setUpAll(() {
registerFallbackValue<PaginationParams>(const PaginationParams()); registerFallbackValue(const PaginationParams());
}); });
List<Channel> _generateChannels( List<Channel> _generateChannels(