Skip to content

Commit

Permalink
Headers emulation and setHeaders method to update headers (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
FZambia authored Jan 25, 2025
1 parent cd958ac commit 4c23682
Show file tree
Hide file tree
Showing 14 changed files with 1,426 additions and 925 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
run: sudo gem install coveralls-lcov

- name: Start Centrifugo
run: docker run -d -p 8000:8000 centrifugo/centrifugo:latest centrifugo --client_insecure
run: docker run -d -p 8000:8000 centrifugo/centrifugo:v6 centrifugo --client.insecure

- name: Run tests
run: bash tool/test.sh
4 changes: 2 additions & 2 deletions example/chat_app/lib/client/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class ChatClient {
url,
ClientConfig(
token: conf.userJwtToken,
headers: <String, dynamic>{
'user-id': chatUserId,
headers: <String, String>{
'user-id': chatUserId.toString(),
'user-name': chatUserName,
},
),
Expand Down
6 changes: 4 additions & 2 deletions example/console/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ void main() async {
url,
centrifuge.ClientConfig(
token: userJwtToken,
// Headers are only supported on platforms that support dart:io
headers: <String, dynamic>{'X-Example-Header': 'example'},
// If you want to use Headers in web environment – make sure your headers use
// string values, centrifuge-dart will then automatically attach them to connect
// frame (using Headers Emulation feature).
headers: <String, String>{'X-Example-Header': 'example'},
));

// State changes.
Expand Down
1 change: 1 addition & 0 deletions example/web_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ environment:
dependencies:
centrifuge:
path: ../../
web: ^1.1.0

publish_to: none

Expand Down
10 changes: 6 additions & 4 deletions example/web_app/web/main.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import 'dart:html';
import 'package:web/web.dart' as web;

import 'package:centrifuge/centrifuge.dart';

void main() {
querySelector('#output')?.text = 'Your Dart app is running.';
web.document.querySelector('#output')?.text = 'Your Dart app is running.';

void onEvent(dynamic event) {
querySelector('#output')?.text = 'client> $event';
web.document.querySelector('#output')?.text = 'client> $event';
}

const url = 'ws://localhost:8000/connection/websocket';
Client client = createClient(
url,
ClientConfig(),
ClientConfig(
headers: <String, String>{'Authorization': 'example'},
),
);

// State changes.
Expand Down
23 changes: 20 additions & 3 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:centrifuge/src/server_subscription.dart';
import 'package:centrifuge/src/transport.dart';
import 'package:meta/meta.dart';

import 'platform/vm.dart' if (dart.library.js_interop) 'platform/js.dart';
import 'proto/client.pb.dart' as protocol;
import 'subscription.dart';

Expand Down Expand Up @@ -50,6 +51,10 @@ abstract class Client {
///
void setToken(String token);

/// Set allows updating connection headers.
///
void setHeaders(Map<String, String> headers);

/// Ready resolves when client successfully connected.
/// Throws exceptions if called not in connecting or connected state.
Future<void> ready();
Expand Down Expand Up @@ -101,6 +106,7 @@ class ClientImpl implements Client {
ClientImpl(this._url, this._config, this._transportBuilder) {
_token = _config.token;
_data = _config.data;
_headers = Map<String, String>.of(_config.headers);
}

final TransportBuilder _transportBuilder;
Expand All @@ -113,6 +119,7 @@ class ClientImpl implements Client {
ClientConfig _config;
ClientConfig get config => _config;

Map<String, String> _headers = {};
String _token = '';
List<int>? _data;
String? _client;
Expand Down Expand Up @@ -197,6 +204,11 @@ class ClientImpl implements Client {
_token = token;
}

@override
void setHeaders(Map<String, String> headers) {
_headers = Map<String, String>.of(headers);
}

@override
Future<void> disconnect() async {
_reconnectAttempts = 0;
Expand Down Expand Up @@ -422,8 +434,8 @@ class ClientImpl implements Client {
return;
}

final transport = _transportBuilder(
url: _url, config: TransportConfig(headers: _config.headers, timeout: _config.timeout));
final transport =
_transportBuilder(url: _url, config: TransportConfig(headers: _headers, timeout: _config.timeout));

try {
await transport.open(_onPush, onError: (dynamic error) {
Expand Down Expand Up @@ -470,6 +482,11 @@ class ClientImpl implements Client {
request.name = _config.name;
request.version = _config.version;

if (isWeb) {
// Use headers emulation in web context.
request.headers.addAll(_headers);
}

if (_serverSubs.isNotEmpty) {
_serverSubs.forEach((key, value) {
final subRequest = protocol.SubscribeRequest();
Expand Down Expand Up @@ -560,7 +577,7 @@ class ClientImpl implements Client {
_inConnect = false;
return;
} else {
_processDisconnect(code: err.code, reason: err.message, reconnect: false);
_processDisconnect(code: err.code, reason: err.message, reconnect: true);
await transport.close();
_inConnect = false;
return;
Expand Down
8 changes: 5 additions & 3 deletions lib/src/client_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ClientConfig {
this.getToken,
this.data,
this.getData,
this.headers = const <String, dynamic>{},
this.headers = const <String, String>{},
this.tlsSkipVerify = false,
this.timeout = const Duration(seconds: 10),
this.minReconnectDelay = const Duration(milliseconds: 500),
Expand All @@ -41,8 +41,10 @@ class ClientConfig {

/// Headers that are set when connecting the web socket on dart:io platforms.
///
/// Note that headers are ignored on the web platform.
final Map<String, dynamic> headers;
/// Note that headers on the web platform use Headers Emulation (since Centrifugo v6)
/// – i.e. headers are sent to Centrifugo in first protocol message but then automatically
/// translated to HTTP headers by Centrifugo in the proxy request to the backend.
final Map<String, String> headers;

final bool tlsSkipVerify;
final Duration minReconnectDelay;
Expand Down
1 change: 1 addition & 0 deletions lib/src/platform/js.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bool get isWeb => true;
1 change: 1 addition & 0 deletions lib/src/platform/vm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bool get isWeb => false;
Loading

0 comments on commit 4c23682

Please sign in to comment.