mirror of
https://github.com/immich-app/immich.git
synced 2026-02-04 00:39:15 +03:00
platform-side headers
This commit is contained in:
@@ -5,6 +5,7 @@ import app.alextran.immich.BuildConfig
|
||||
import okhttp3.Cache
|
||||
import okhttp3.ConnectionPool
|
||||
import okhttp3.Dispatcher
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.File
|
||||
@@ -38,6 +39,7 @@ object HttpClientManager {
|
||||
|
||||
private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
|
||||
|
||||
var headers: Headers = Headers.headersOf("User-Agent", USER_AGENT)
|
||||
val isMtls: Boolean get() = keyStore.containsAlias(CERT_ALIAS)
|
||||
|
||||
fun initialize(context: Context) {
|
||||
@@ -92,6 +94,12 @@ object HttpClientManager {
|
||||
synchronized(this) { clientChangedListeners.add(listener) }
|
||||
}
|
||||
|
||||
fun setRequestHeaders(headerMap: Map<String, String>) {
|
||||
val builder = Headers.Builder()
|
||||
headerMap.forEach { (key, value) -> builder.add(key, value) }
|
||||
headers = builder.build()
|
||||
}
|
||||
|
||||
private fun build(cacheDir: File): OkHttpClient {
|
||||
val connectionPool = ConnectionPool(
|
||||
maxIdleConnections = KEEP_ALIVE_CONNECTIONS,
|
||||
@@ -107,8 +115,10 @@ object HttpClientManager {
|
||||
.apply { init(arrayOf(DynamicKeyManager()), arrayOf(trustManager), null) }
|
||||
|
||||
return OkHttpClient.Builder()
|
||||
.addInterceptor { chain ->
|
||||
chain.proceed(chain.request().newBuilder().header("User-Agent", USER_AGENT).build())
|
||||
.addInterceptor {
|
||||
val builder = it.request().newBuilder()
|
||||
headers.forEach { (key, value) -> builder.addHeader(key, value) }
|
||||
it.proceed(builder.build())
|
||||
}
|
||||
.connectionPool(connectionPool)
|
||||
.dispatcher(Dispatcher().apply { maxRequestsPerHost = MAX_REQUESTS_PER_HOST })
|
||||
|
||||
@@ -228,6 +228,7 @@ interface NetworkApi {
|
||||
* iOS only - Android should use OkHttpWebSocket.connectWithClient directly.
|
||||
*/
|
||||
fun createWebSocketTask(url: String, protocols: List<String>?, callback: (Result<WebSocketTaskResult>) -> Unit)
|
||||
fun setRequestHeaders(headers: Map<String, String>)
|
||||
|
||||
companion object {
|
||||
/** The codec used by NetworkApi. */
|
||||
@@ -330,6 +331,24 @@ interface NetworkApi {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.NetworkApi.setRequestHeaders$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val headersArg = args[0] as Map<String, String>
|
||||
val wrapped: List<Any?> = try {
|
||||
api.setRequestHeaders(headersArg)
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
NetworkPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,17 @@ private class NetworkApiImpl(private val context: Context) : NetworkApi {
|
||||
return NativeBuffer.createGlobalRef(client)
|
||||
}
|
||||
|
||||
// only used on iOS
|
||||
override fun createWebSocketTask(
|
||||
url: String,
|
||||
protocols: List<String>?,
|
||||
callback: (Result<WebSocketTaskResult>) -> Unit
|
||||
) {}
|
||||
|
||||
override fun setRequestHeaders(headers: Map<String, String>) {
|
||||
HttpClientManager.setRequestHeaders(headers)
|
||||
}
|
||||
|
||||
private fun handlePickedFile(uri: Uri) {
|
||||
val callback = pendingCallback ?: return
|
||||
pendingCallback = null
|
||||
|
||||
@@ -47,7 +47,7 @@ private open class RemoteImagesPigeonCodec : StandardMessageCodec() {
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface RemoteImageApi {
|
||||
fun requestImage(url: String, headers: Map<String, String>, requestId: Long, callback: (Result<Map<String, Long>?>) -> Unit)
|
||||
fun requestImage(url: String, requestId: Long, callback: (Result<Map<String, Long>?>) -> Unit)
|
||||
fun cancelRequest(requestId: Long)
|
||||
fun clearCache(callback: (Result<Long>) -> Unit)
|
||||
|
||||
@@ -66,9 +66,8 @@ interface RemoteImageApi {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val urlArg = args[0] as String
|
||||
val headersArg = args[1] as Map<String, String>
|
||||
val requestIdArg = args[2] as Long
|
||||
api.requestImage(urlArg, headersArg, requestIdArg) { result: Result<Map<String, Long>?> ->
|
||||
val requestIdArg = args[1] as Long
|
||||
api.requestImage(urlArg, requestIdArg) { result: Result<Map<String, Long>?> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(RemoteImagesPigeonUtils.wrapError(error))
|
||||
|
||||
@@ -49,7 +49,6 @@ class RemoteImagesImpl(context: Context) : RemoteImageApi {
|
||||
|
||||
override fun requestImage(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
requestId: Long,
|
||||
callback: (Result<Map<String, Long>?>) -> Unit
|
||||
) {
|
||||
@@ -58,7 +57,6 @@ class RemoteImagesImpl(context: Context) : RemoteImageApi {
|
||||
|
||||
ImageFetcherManager.fetch(
|
||||
url,
|
||||
headers,
|
||||
signal,
|
||||
onSuccess = { buffer ->
|
||||
requestMap.remove(requestId)
|
||||
@@ -119,12 +117,11 @@ private object ImageFetcherManager {
|
||||
|
||||
fun fetch(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
signal: CancellationSignal,
|
||||
onSuccess: (NativeByteBuffer) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
) {
|
||||
fetcher.fetch(url, headers, signal, onSuccess, onFailure)
|
||||
fetcher.fetch(url, signal, onSuccess, onFailure)
|
||||
}
|
||||
|
||||
fun clearCache(onCleared: (Result<Long>) -> Unit) {
|
||||
@@ -151,7 +148,6 @@ private object ImageFetcherManager {
|
||||
private sealed interface ImageFetcher {
|
||||
fun fetch(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
signal: CancellationSignal,
|
||||
onSuccess: (NativeByteBuffer) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
@@ -178,7 +174,6 @@ private class CronetImageFetcher(context: Context, cacheDir: File) : ImageFetche
|
||||
|
||||
override fun fetch(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
signal: CancellationSignal,
|
||||
onSuccess: (NativeByteBuffer) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
@@ -193,7 +188,7 @@ private class CronetImageFetcher(context: Context, cacheDir: File) : ImageFetche
|
||||
|
||||
val callback = FetchCallback(onSuccess, onFailure, ::onComplete)
|
||||
val requestBuilder = engine.newUrlRequestBuilder(url, callback, executor)
|
||||
headers.forEach { (key, value) -> requestBuilder.addHeader(key, value) }
|
||||
HttpClientManager.headers.forEach { (key, value) -> requestBuilder.addHeader(key, value) }
|
||||
val request = requestBuilder.build()
|
||||
signal.setOnCancelListener(request::cancel)
|
||||
request.start()
|
||||
@@ -390,7 +385,6 @@ private class OkHttpImageFetcher private constructor(
|
||||
|
||||
override fun fetch(
|
||||
url: String,
|
||||
headers: Map<String, String>,
|
||||
signal: CancellationSignal,
|
||||
onSuccess: (NativeByteBuffer) -> Unit,
|
||||
onFailure: (Exception) -> Unit,
|
||||
@@ -403,7 +397,6 @@ private class OkHttpImageFetcher private constructor(
|
||||
}
|
||||
|
||||
val requestBuilder = Request.Builder().url(url)
|
||||
headers.forEach { (key, value) -> requestBuilder.addHeader(key, value) }
|
||||
val call = client.newCall(requestBuilder.build())
|
||||
signal.setOnCancelListener(call::cancel)
|
||||
|
||||
|
||||
@@ -261,6 +261,7 @@ protocol NetworkApi {
|
||||
/// Creates a WebSocket task and waits for connection to be established.
|
||||
/// iOS only - Android should use OkHttpWebSocket.connectWithClient directly.
|
||||
func createWebSocketTask(url: String, protocols: [String]?, completion: @escaping (Result<WebSocketTaskResult, Error>) -> Void)
|
||||
func setRequestHeaders(headers: [String: String]) throws
|
||||
}
|
||||
|
||||
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
|
||||
@@ -351,5 +352,20 @@ class NetworkApiSetup {
|
||||
} else {
|
||||
createWebSocketTaskChannel.setMessageHandler(nil)
|
||||
}
|
||||
let setRequestHeadersChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.immich_mobile.NetworkApi.setRequestHeaders\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec)
|
||||
if let api = api {
|
||||
setRequestHeadersChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let headersArg = args[0] as! [String: String]
|
||||
do {
|
||||
try api.setRequestHeaders(headers: headersArg)
|
||||
reply(wrapResult(nil))
|
||||
} catch {
|
||||
reply(wrapError(error))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setRequestHeadersChannel.setMessageHandler(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,10 @@ class NetworkApiImpl: NetworkApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setRequestHeaders(headers: [String : String]) throws {
|
||||
URLSessionManager.shared.session.configuration.httpAdditionalHeaders = headers
|
||||
}
|
||||
}
|
||||
|
||||
private class CertImporter: NSObject, UIDocumentPickerDelegate {
|
||||
|
||||
@@ -70,7 +70,7 @@ class RemoteImagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable
|
||||
|
||||
/// Generated protocol from Pigeon that represents a handler of messages from Flutter.
|
||||
protocol RemoteImageApi {
|
||||
func requestImage(url: String, headers: [String: String], requestId: Int64, completion: @escaping (Result<[String: Int64]?, Error>) -> Void)
|
||||
func requestImage(url: String, requestId: Int64, completion: @escaping (Result<[String: Int64]?, Error>) -> Void)
|
||||
func cancelRequest(requestId: Int64) throws
|
||||
func clearCache(completion: @escaping (Result<Int64, Error>) -> Void)
|
||||
}
|
||||
@@ -86,9 +86,8 @@ class RemoteImageApiSetup {
|
||||
requestImageChannel.setMessageHandler { message, reply in
|
||||
let args = message as! [Any?]
|
||||
let urlArg = args[0] as! String
|
||||
let headersArg = args[1] as! [String: String]
|
||||
let requestIdArg = args[2] as! Int64
|
||||
api.requestImage(url: urlArg, headers: headersArg, requestId: requestIdArg) { result in
|
||||
let requestIdArg = args[1] as! Int64
|
||||
api.requestImage(url: urlArg, requestId: requestIdArg) { result in
|
||||
switch result {
|
||||
case .success(let res):
|
||||
reply(wrapResult(res))
|
||||
|
||||
@@ -33,12 +33,9 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
|
||||
kCGImageSourceCreateThumbnailFromImageAlways: true
|
||||
] as CFDictionary
|
||||
|
||||
func requestImage(url: String, headers: [String : String], requestId: Int64, completion: @escaping (Result<[String : Int64]?, any Error>) -> Void) {
|
||||
func requestImage(url: String, requestId: Int64, completion: @escaping (Result<[String : Int64]?, any Error>) -> Void) {
|
||||
var urlRequest = URLRequest(url: URL(string: url)!)
|
||||
urlRequest.cachePolicy = .returnCacheDataElseLoad
|
||||
for (key, value) in headers {
|
||||
urlRequest.setValue(value, forHTTPHeaderField: key)
|
||||
}
|
||||
|
||||
let task = URLSessionManager.shared.session.dataTask(with: urlRequest) { data, response, error in
|
||||
Self.handleCompletion(requestId: requestId, data: data, response: response, error: error)
|
||||
|
||||
@@ -2,9 +2,8 @@ part of 'image_request.dart';
|
||||
|
||||
class RemoteImageRequest extends ImageRequest {
|
||||
final String uri;
|
||||
final Map<String, String> headers;
|
||||
|
||||
RemoteImageRequest({required this.uri, required this.headers});
|
||||
RemoteImageRequest({required this.uri});
|
||||
|
||||
@override
|
||||
Future<ImageInfo?> load(ImageDecoderCallback decode, {double scale = 1.0}) async {
|
||||
@@ -12,7 +11,7 @@ class RemoteImageRequest extends ImageRequest {
|
||||
return null;
|
||||
}
|
||||
|
||||
final info = await remoteImageApi.requestImage(uri, headers: headers, requestId: requestId);
|
||||
final info = await remoteImageApi.requestImage(uri, requestId: requestId);
|
||||
final frame = switch (info) {
|
||||
{'pointer': int pointer, 'length': int length} => await _fromEncodedPlatformImage(pointer, length),
|
||||
{'pointer': int pointer, 'width': int width, 'height': int height, 'rowBytes': int rowBytes} =>
|
||||
|
||||
@@ -60,7 +60,7 @@ class NetworkRepository {
|
||||
final result = await networkApi.createWebSocketTask(uri.toString(), protocols?.toList());
|
||||
final pointer = Pointer.fromAddress(result.taskPointer);
|
||||
final task = URLSessionWebSocketTask.fromRawPointer(pointer.cast());
|
||||
return CupertinoWebSocket.fromConnectedTask(task, protocol: result.protocol ?? '');
|
||||
return CupertinoWebSocket.fromConnectedTask(task, protocol: result.taskProtocol ?? '');
|
||||
}
|
||||
|
||||
static Future<WebSocket> _createAndroidWebSocket(Uri uri, {Iterable<String>? protocols}) {
|
||||
|
||||
@@ -36,10 +36,6 @@ class SyncApiRepository {
|
||||
|
||||
final headers = {'Content-Type': 'application/json', 'Accept': 'application/jsonlines+json'};
|
||||
|
||||
final headerParams = <String, String>{};
|
||||
await _api.applyToParams([], headerParams);
|
||||
headers.addAll(headerParams);
|
||||
|
||||
final shouldReset = Store.get(StoreKey.shouldResetSync, false);
|
||||
final request = http.Request('POST', Uri.parse(endpoint));
|
||||
request.headers.addAll(headers);
|
||||
|
||||
@@ -8,6 +8,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||
import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/generated/intl_keys.g.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
|
||||
class SettingsHeader {
|
||||
String key = "";
|
||||
@@ -20,7 +22,6 @@ class HeaderSettingsPage extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// final apiService = ref.watch(apiServiceProvider);
|
||||
final headers = useState<List<SettingsHeader>>([]);
|
||||
final setInitialHeaders = useState(false);
|
||||
|
||||
@@ -87,7 +88,7 @@ class HeaderSettingsPage extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
saveHeaders(List<SettingsHeader> headers) {
|
||||
saveHeaders(List<SettingsHeader> headers) async {
|
||||
final headersMap = {};
|
||||
for (var header in headers) {
|
||||
final key = header.key.trim();
|
||||
@@ -98,7 +99,8 @@ class HeaderSettingsPage extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
var encoded = jsonEncode(headersMap);
|
||||
Store.put(StoreKey.customHeaders, encoded);
|
||||
await Store.put(StoreKey.customHeaders, encoded);
|
||||
await networkApi.setRequestHeaders(ApiService.getRequestHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
mobile/lib/platform/network_api.g.dart
generated
23
mobile/lib/platform/network_api.g.dart
generated
@@ -329,4 +329,27 @@ class NetworkApi {
|
||||
return (pigeonVar_replyList[0] as WebSocketTaskResult?)!;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setRequestHeaders(Map<String, String> headers) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.immich_mobile.NetworkApi.setRequestHeaders$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
pigeonVar_channelName,
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[headers]);
|
||||
final List<Object?>? pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
} else if (pigeonVar_replyList.length > 1) {
|
||||
throw PlatformException(
|
||||
code: pigeonVar_replyList[0]! as String,
|
||||
message: pigeonVar_replyList[1] as String?,
|
||||
details: pigeonVar_replyList[2],
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
mobile/lib/platform/remote_image_api.g.dart
generated
8
mobile/lib/platform/remote_image_api.g.dart
generated
@@ -49,11 +49,7 @@ class RemoteImageApi {
|
||||
|
||||
final String pigeonVar_messageChannelSuffix;
|
||||
|
||||
Future<Map<String, int>?> requestImage(
|
||||
String url, {
|
||||
required Map<String, String> headers,
|
||||
required int requestId,
|
||||
}) async {
|
||||
Future<Map<String, int>?> requestImage(String url, {required int requestId}) async {
|
||||
final String pigeonVar_channelName =
|
||||
'dev.flutter.pigeon.immich_mobile.RemoteImageApi.requestImage$pigeonVar_messageChannelSuffix';
|
||||
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
|
||||
@@ -61,7 +57,7 @@ class RemoteImageApi {
|
||||
pigeonChannelCodec,
|
||||
binaryMessenger: pigeonVar_binaryMessenger,
|
||||
);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[url, headers, requestId]);
|
||||
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[url, requestId]);
|
||||
final List<Object?>? pigeonVar_replyList = await pigeonVar_sendFuture as List<Object?>?;
|
||||
if (pigeonVar_replyList == null) {
|
||||
throw _createConnectionError(pigeonVar_channelName);
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:immich_mobile/domain/services/setting.service.dart';
|
||||
import 'package:immich_mobile/infrastructure/loaders/image_request.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/one_frame_multi_image_stream_completer.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
|
||||
@@ -37,7 +36,7 @@ class RemoteImageProvider extends CancellableImageProvider<RemoteImageProvider>
|
||||
}
|
||||
|
||||
Stream<ImageInfo> _codec(RemoteImageProvider key, ImageDecoderCallback decode) {
|
||||
final request = this.request = RemoteImageRequest(uri: key.url, headers: ApiService.getRequestHeaders());
|
||||
final request = this.request = RemoteImageRequest(uri: key.url);
|
||||
return loadRequest(request, decode);
|
||||
}
|
||||
|
||||
@@ -88,10 +87,8 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
return;
|
||||
}
|
||||
|
||||
final headers = ApiService.getRequestHeaders();
|
||||
final previewRequest = request = RemoteImageRequest(
|
||||
uri: getThumbnailUrlForRemoteId(key.assetId, type: AssetMediaSize.preview, thumbhash: key.thumbhash),
|
||||
headers: headers,
|
||||
);
|
||||
yield* loadRequest(previewRequest, decode);
|
||||
|
||||
@@ -104,7 +101,7 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
return;
|
||||
}
|
||||
|
||||
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId), headers: headers);
|
||||
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId));
|
||||
yield* loadRequest(originalRequest, decode);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:immich_mobile/entities/store.entity.dart';
|
||||
import 'package:immich_mobile/models/auth/auth_state.model.dart';
|
||||
import 'package:immich_mobile/models/auth/login_response.model.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/user.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/auth.service.dart';
|
||||
@@ -124,6 +125,7 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
||||
|
||||
Future<bool> saveAuthInfo({required String accessToken}) async {
|
||||
await _apiService.setAccessToken(accessToken);
|
||||
await networkApi.setRequestHeaders(ApiService.getRequestHeaders());
|
||||
|
||||
final serverEndpoint = Store.get(StoreKey.serverEndpoint);
|
||||
final customHeaders = Store.tryGet(StoreKey.customHeaders);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -13,7 +12,6 @@ import 'package:immich_mobile/providers/auth.provider.dart';
|
||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||
import 'package:immich_mobile/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/services/sync.service.dart';
|
||||
import 'package:immich_mobile/utils/debounce.dart';
|
||||
import 'package:immich_mobile/utils/debug_print.dart';
|
||||
@@ -100,11 +98,6 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
if (authenticationState.isAuthenticated) {
|
||||
try {
|
||||
final endpoint = Uri.parse(Store.get(StoreKey.serverEndpoint));
|
||||
final headers = ApiService.getRequestHeaders();
|
||||
if (endpoint.userInfo.isNotEmpty) {
|
||||
headers["Authorization"] = "Basic ${base64.encode(utf8.encode(endpoint.userInfo))}";
|
||||
}
|
||||
|
||||
dPrint(() => "Attempting to connect to websocket");
|
||||
// Configure socket transports must be specified
|
||||
Socket socket = io(
|
||||
@@ -117,7 +110,6 @@ class WebsocketNotifier extends StateNotifier<WebsocketState> {
|
||||
.enableForceNew()
|
||||
.enableForceNewConnection()
|
||||
.enableAutoConnect()
|
||||
.setExtraHeaders(headers)
|
||||
.build(),
|
||||
);
|
||||
|
||||
|
||||
@@ -129,11 +129,8 @@ class ApiService implements Authentication {
|
||||
|
||||
Future<String> _getWellKnownEndpoint(String baseUrl) async {
|
||||
try {
|
||||
var headers = {"Accept": "application/json"};
|
||||
headers.addAll(getRequestHeaders());
|
||||
|
||||
final res = await NetworkRepository.client
|
||||
.get(Uri.parse("$baseUrl/.well-known/immich"), headers: headers)
|
||||
.get(Uri.parse("$baseUrl/.well-known/immich"))
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
@@ -197,10 +194,7 @@ class ApiService implements Authentication {
|
||||
|
||||
@override
|
||||
Future<void> applyToParams(List<QueryParam> queryParams, Map<String, String> headerParams) {
|
||||
return Future<void>(() {
|
||||
var headers = ApiService.getRequestHeaders();
|
||||
headerParams.addAll(headers);
|
||||
});
|
||||
return Future.value();
|
||||
}
|
||||
|
||||
ApiClient get apiClient => _apiClient;
|
||||
|
||||
@@ -68,7 +68,7 @@ class AuthService {
|
||||
|
||||
try {
|
||||
final uri = Uri.parse('$url/users/me');
|
||||
final response = await NetworkRepository.client.get(uri, headers: ApiService.getRequestHeaders());
|
||||
final response = await NetworkRepository.client.get(uri);
|
||||
if (response.statusCode == 200) {
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
@@ -52,4 +52,6 @@ abstract class NetworkApi {
|
||||
/// iOS only - Android should use OkHttpWebSocket.connectWithClient directly.
|
||||
@async
|
||||
WebSocketTaskResult createWebSocketTask(String url, List<String>? protocols);
|
||||
|
||||
void setRequestHeaders(Map<String, String> headers);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import 'package:pigeon/pigeon.dart';
|
||||
dartOut: 'lib/platform/remote_image_api.g.dart',
|
||||
swiftOut: 'ios/Runner/Images/RemoteImages.g.swift',
|
||||
swiftOptions: SwiftOptions(includeErrorClass: false),
|
||||
kotlinOut:
|
||||
'android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt',
|
||||
kotlinOut: 'android/app/src/main/kotlin/app/alextran/immich/images/RemoteImages.g.kt',
|
||||
kotlinOptions: KotlinOptions(package: 'app.alextran.immich.images', includeErrorClass: false),
|
||||
dartOptions: DartOptions(),
|
||||
dartPackageName: 'immich_mobile',
|
||||
@@ -15,11 +14,7 @@ import 'package:pigeon/pigeon.dart';
|
||||
@HostApi()
|
||||
abstract class RemoteImageApi {
|
||||
@async
|
||||
Map<String, int>? requestImage(
|
||||
String url, {
|
||||
required Map<String, String> headers,
|
||||
required int requestId,
|
||||
});
|
||||
Map<String, int>? requestImage(String url, {required int requestId});
|
||||
|
||||
void cancelRequest(int requestId);
|
||||
|
||||
|
||||
@@ -333,8 +333,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "pkgs/cupertino_http"
|
||||
ref: "114b2807bdeee641457b5703f411318d722b67b5"
|
||||
resolved-ref: "114b2807bdeee641457b5703f411318d722b67b5"
|
||||
ref: "398fcc427e1a15a08ea9ddb467bb8368e1acc09d"
|
||||
resolved-ref: "398fcc427e1a15a08ea9ddb467bb8368e1acc09d"
|
||||
url: "https://github.com/mertalev/http"
|
||||
source: git
|
||||
version: "3.0.0-wip"
|
||||
@@ -1267,8 +1267,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "pkgs/ok_http"
|
||||
ref: "114b2807bdeee641457b5703f411318d722b67b5"
|
||||
resolved-ref: "114b2807bdeee641457b5703f411318d722b67b5"
|
||||
ref: "398fcc427e1a15a08ea9ddb467bb8368e1acc09d"
|
||||
resolved-ref: "398fcc427e1a15a08ea9ddb467bb8368e1acc09d"
|
||||
url: "https://github.com/mertalev/http"
|
||||
source: git
|
||||
version: "0.1.1-wip"
|
||||
@@ -1727,19 +1727,20 @@ packages:
|
||||
socket_io_client:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: socket_io_client
|
||||
sha256: ede469f3e4c55e8528b4e023bdedbc20832e8811ab9b61679d1ba3ed5f01f23b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3+1"
|
||||
path: "."
|
||||
ref: "95a61e3d92b0ad0d70ba488b9cb4598a3d655c36"
|
||||
resolved-ref: "95a61e3d92b0ad0d70ba488b9cb4598a3d655c36"
|
||||
url: "https://github.com/mertalev/socket.io-client-dart"
|
||||
source: git
|
||||
version: "3.1.4"
|
||||
socket_io_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socket_io_common
|
||||
sha256: "2ab92f8ff3ebbd4b353bf4a98bee45cc157e3255464b2f90f66e09c4472047eb"
|
||||
sha256: "162fbaecbf4bf9a9372a62a341b3550b51dcef2f02f3e5830a297fd48203d45b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
version: "3.1.1"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2101,21 +2102,21 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
version: "3.0.3"
|
||||
webdriver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -75,7 +75,6 @@ dependencies:
|
||||
share_handler: ^0.0.25
|
||||
share_plus: ^10.1.4
|
||||
sliver_tools: ^0.2.12
|
||||
socket_io_client: ^2.0.3+1
|
||||
stream_transform: ^2.1.1
|
||||
thumbhash: 0.1.0+1
|
||||
timezone: ^0.9.4
|
||||
@@ -83,16 +82,21 @@ dependencies:
|
||||
uuid: ^4.5.1
|
||||
wakelock_plus: ^1.3.0
|
||||
worker_manager: ^7.2.7
|
||||
web_socket: ^1.0.1
|
||||
# TODO: upstream these changes
|
||||
socket_io_client:
|
||||
git:
|
||||
url: https://github.com/mertalev/socket.io-client-dart
|
||||
ref: '95a61e3d92b0ad0d70ba488b9cb4598a3d655c36'
|
||||
cupertino_http:
|
||||
git:
|
||||
url: https://github.com/mertalev/http
|
||||
ref: '114b2807bdeee641457b5703f411318d722b67b5'
|
||||
ref: '398fcc427e1a15a08ea9ddb467bb8368e1acc09d'
|
||||
path: pkgs/cupertino_http/
|
||||
ok_http:
|
||||
git:
|
||||
url: https://github.com/mertalev/http
|
||||
ref: '114b2807bdeee641457b5703f411318d722b67b5'
|
||||
ref: '398fcc427e1a15a08ea9ddb467bb8368e1acc09d'
|
||||
path: pkgs/ok_http/
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Reference in New Issue
Block a user