Start writing the web app
All checks were successful
ci/woodpecker/push/build Pipeline was successful
All checks were successful
ci/woodpecker/push/build Pipeline was successful
Signed-off-by: Nikolai Rodionov <allanger@posteo.com>
This commit was merged in pull request #5.
This commit is contained in:
71
lib/core/grpc/grpc_auth_interceptor.dart
Normal file
71
lib/core/grpc/grpc_auth_interceptor.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:grpc/grpc.dart';
|
||||
|
||||
class AuthInterceptor extends ClientInterceptor {
|
||||
final String Function() getAccessToken;
|
||||
final String Function() getRefreshToken;
|
||||
|
||||
AuthInterceptor({
|
||||
required this.getAccessToken,
|
||||
required this.getRefreshToken,
|
||||
});
|
||||
|
||||
bool _isPublicEndpoint(String path) {
|
||||
return path.contains('/Public');
|
||||
}
|
||||
|
||||
bool _isRefreshEndpoint(String path) {
|
||||
return path.contains('/RefreshToken');
|
||||
}
|
||||
|
||||
Map<String, String> _buildMetadata(String path) {
|
||||
final metadata = <String, String>{};
|
||||
|
||||
// Public endpoints → no token
|
||||
if (_isPublicEndpoint(path)) {
|
||||
log("Public endpoint, no tokens needed");
|
||||
return metadata;
|
||||
}
|
||||
|
||||
String? token;
|
||||
|
||||
// Refresh endpoint → use refresh token
|
||||
if (_isRefreshEndpoint(path)) {
|
||||
log("Adding a refresh token to the metadata");
|
||||
token = getRefreshToken();
|
||||
} else {
|
||||
log("Adding an acces token to the metadata");
|
||||
token = getAccessToken();
|
||||
}
|
||||
|
||||
if (token.isNotEmpty) {
|
||||
metadata['authorization'] = 'Bearer $token';
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@override
|
||||
ResponseStream<R> interceptStreaming<Q, R>(
|
||||
ClientMethod<Q, R> method,
|
||||
Stream<Q> requests,
|
||||
CallOptions options,
|
||||
ClientStreamingInvoker<Q, R> invoker,
|
||||
) {
|
||||
// TODO: implement interceptStreaming
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
ResponseFuture<R> interceptUnary<Q, R>(
|
||||
ClientMethod<Q, R> method,
|
||||
Q request,
|
||||
CallOptions options,
|
||||
ClientUnaryInvoker<Q, R> invoker,
|
||||
) {
|
||||
final modifiedOptions = options.mergedWith(
|
||||
CallOptions(metadata: _buildMetadata(method.path)),
|
||||
);
|
||||
return super.interceptUnary(method, request, modifiedOptions, invoker);
|
||||
}
|
||||
}
|
||||
16
lib/core/grpc/grpc_channel_provider.dart
Normal file
16
lib/core/grpc/grpc_channel_provider.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:grpc/grpc_web.dart';
|
||||
|
||||
final grpcChannelProvider = Provider<GrpcWebClientChannel>((ref) {
|
||||
String backendURL = dotenv.env['SOFTPLAYER_BACKEND_URL']!;
|
||||
final GrpcWebClientChannel channel = GrpcWebClientChannel.xhr(
|
||||
Uri.parse(backendURL),
|
||||
);
|
||||
|
||||
ref.onDispose(() async {
|
||||
await channel.shutdown();
|
||||
});
|
||||
|
||||
return channel;
|
||||
});
|
||||
54
lib/core/grpc/grpc_client.dart
Normal file
54
lib/core/grpc/grpc_client.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:softplayer_dart_proto/accounts/v1/accounts_v1.pbgrpc.dart';
|
||||
import 'package:softplayer_dart_proto/test/v1/test_v1.pbgrpc.dart';
|
||||
import 'package:softplayer_web/core/grpc/grpc_auth_interceptor.dart';
|
||||
import 'package:softplayer_web/core/tokens/application/tokens_application.dart';
|
||||
|
||||
import 'grpc_channel_provider.dart';
|
||||
|
||||
final testServiceClientProvider = Provider<TestServiceClient>((ref) {
|
||||
final channel = ref.watch(grpcChannelProvider);
|
||||
final tokenState = ref.read(tokensControllerProvider).value;
|
||||
if (tokenState == null) {
|
||||
throw Exception("Token state is not initialized");
|
||||
}
|
||||
|
||||
return TestServiceClient(
|
||||
channel,
|
||||
interceptors: [
|
||||
AuthInterceptor(
|
||||
getAccessToken: tokenState.getAccessToken,
|
||||
getRefreshToken: tokenState.getRefreshToken,
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
final accountsServiceClientProvider = Provider<AccountsServiceClient>((ref) {
|
||||
final channel = ref.watch(grpcChannelProvider);
|
||||
final tokenState = ref.read(tokensControllerProvider).value;
|
||||
if (tokenState == null) {
|
||||
throw Exception("Token state is not initialized");
|
||||
}
|
||||
return AccountsServiceClient(
|
||||
channel,
|
||||
interceptors: [
|
||||
AuthInterceptor(
|
||||
getAccessToken: tokenState.getAccessToken,
|
||||
getRefreshToken: tokenState.getRefreshToken,
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
final publicAccountsServiceClientProvider =
|
||||
Provider<PublicAccountsServiceClient>((ref) {
|
||||
final channel = ref.watch(grpcChannelProvider);
|
||||
return PublicAccountsServiceClient(channel);
|
||||
});
|
||||
|
||||
final refreshSessionServiceClientProvider =
|
||||
Provider<RefreshSessionServiceClient>((ref) {
|
||||
final channel = ref.watch(grpcChannelProvider);
|
||||
return RefreshSessionServiceClient(channel);
|
||||
});
|
||||
Reference in New Issue
Block a user