add socket.io
This commit is contained in:
		
							parent
							
								
									24f8ef9c55
								
							
						
					
					
						commit
						ee17456dcd
					
				
							
								
								
									
										159
									
								
								index2.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								index2.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,159 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
    <title>Socket.IO Test Client</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        body { font-family: sans-serif; display: flex; flex-direction: column; max-width: 800px; margin: auto; }
 | 
			
		||||
        .controls, .message-box { border: 1px solid #ccc; padding: 10px; margin-bottom: 10px; border-radius: 5px; }
 | 
			
		||||
        input[type="text"] { width: calc(100% - 100px); padding: 8px; margin-right: 5px; }
 | 
			
		||||
        button { padding: 8px 12px; }
 | 
			
		||||
        #messages { border: 1px solid #eee; padding: 10px; height: 300px; overflow-y: scroll; background-color: #f9f9f9; }
 | 
			
		||||
        .msg { margin: 5px 0; padding: 5px; border-radius: 3px; }
 | 
			
		||||
        .server-msg { background-color: #e1f5fe; }
 | 
			
		||||
        .client-msg { background-color: #c8e6c9; text-align: right; }
 | 
			
		||||
        .status-msg { background-color: #fff9c4; text-align: center; font-style: italic; }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Socket.IO Test Client</h1>
 | 
			
		||||
 | 
			
		||||
    <div class="controls">
 | 
			
		||||
        <h3>Подключение</h3>
 | 
			
		||||
        <input type="text" id="url" placeholder="Сервер URL" value="https://127.0.0.1:5205/">
 | 
			
		||||
        <input type="text" id="token" placeholder="Токен (для auth)" value="my-secret-token-123">
 | 
			
		||||
        <button id="connectBtn">Подключиться</button>
 | 
			
		||||
        <button id="disconnectBtn" disabled>Отключиться</button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="message-box">
 | 
			
		||||
        <h3>Отправка клиентского сообщения</h3>
 | 
			
		||||
        <input type="text" id="message" placeholder="Введите сообщение" disabled>
 | 
			
		||||
        <button id="sendBtn" disabled>Отправить</button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="controls">
 | 
			
		||||
        <h3>Настройки</h3>
 | 
			
		||||
        <label>
 | 
			
		||||
            <input type="checkbox" id="invertLogs">
 | 
			
		||||
            Новый сверху (инвертировать лог)
 | 
			
		||||
        </label>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <h3>Логи <button id="clearLogBtn" style="font-size: 0.8em; float: right;">Очистить</button></h3>
 | 
			
		||||
    <div id="messages"></div>
 | 
			
		||||
 | 
			
		||||
    <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
 | 
			
		||||
    <script>
 | 
			
		||||
        const urlInput = document.getElementById('url');
 | 
			
		||||
        const tokenInput = document.getElementById('token');
 | 
			
		||||
        const connectBtn = document.getElementById('connectBtn');
 | 
			
		||||
        const disconnectBtn = document.getElementById('disconnectBtn');
 | 
			
		||||
        const messageInput = document.getElementById('message');
 | 
			
		||||
        const sendBtn = document.getElementById('sendBtn');
 | 
			
		||||
        const messagesDiv = document.getElementById('messages');
 | 
			
		||||
        const clearLogBtn = document.getElementById('clearLogBtn');
 | 
			
		||||
        const invertLogsCheckbox = document.getElementById('invertLogs');
 | 
			
		||||
 | 
			
		||||
        let socket = null;
 | 
			
		||||
 | 
			
		||||
        function logMessage(message, type = 'status') {
 | 
			
		||||
            const ts = new Date().toLocaleTimeString();
 | 
			
		||||
            const newLogEntry = `<div class="msg ${type}-msg">[${ts}] ${message}</div>`;
 | 
			
		||||
            if (invertLogsCheckbox.checked) {
 | 
			
		||||
                messagesDiv.innerHTML = newLogEntry + messagesDiv.innerHTML;
 | 
			
		||||
                messagesDiv.scrollTop = 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                messagesDiv.innerHTML += newLogEntry;
 | 
			
		||||
                messagesDiv.scrollTop = messagesDiv.scrollHeight;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function connectToServer() {
 | 
			
		||||
            if (socket) {
 | 
			
		||||
                logMessage('Уже подключены. Сначала отключитесь.', 'status');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            const token = tokenInput.value;
 | 
			
		||||
            const url = urlInput.value || 'https://127.0.0.1:5205/';
 | 
			
		||||
            logMessage('Подключаемся к серверу...', 'status');
 | 
			
		||||
 | 
			
		||||
            socket = io(url, {
 | 
			
		||||
                auth: {
 | 
			
		||||
                    token: token || null
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Универсальный перехват всех событий
 | 
			
		||||
            socket.onAny((event, ...args) => {
 | 
			
		||||
                try {
 | 
			
		||||
                    logMessage(`onAny -> ${event}: ${JSON.stringify(args[0])}`, 'server');
 | 
			
		||||
                } catch (e) {
 | 
			
		||||
                    logMessage(`onAny -> ${event}: <unserializable>`, 'server');
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            socket.on('connect', () => {
 | 
			
		||||
                logMessage(`Успешное подключение! SID: ${socket.id}`, 'status');
 | 
			
		||||
                connectBtn.disabled = true;
 | 
			
		||||
                disconnectBtn.disabled = false;
 | 
			
		||||
                messageInput.disabled = false;
 | 
			
		||||
                sendBtn.disabled = false;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            socket.on('disconnect', () => {
 | 
			
		||||
                logMessage('Отключено от сервера.', 'status');
 | 
			
		||||
                connectBtn.disabled = false;
 | 
			
		||||
                disconnectBtn.disabled = true;
 | 
			
		||||
                messageInput.disabled = true;
 | 
			
		||||
                sendBtn.disabled = true;
 | 
			
		||||
                socket = null;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Часто используемые события
 | 
			
		||||
            socket.on('message', (data) => {
 | 
			
		||||
                logMessage(`message: ${JSON.stringify(data)}`, 'server');
 | 
			
		||||
            });
 | 
			
		||||
            socket.on('connected', (data) => {
 | 
			
		||||
                logMessage(`connected: ${JSON.stringify(data)}`, 'server');
 | 
			
		||||
            });
 | 
			
		||||
            socket.on('chat:new_message', (data) => {
 | 
			
		||||
                logMessage(`chat:new_message: ${JSON.stringify(data)}`, 'server');
 | 
			
		||||
            });
 | 
			
		||||
            socket.on('achievement:received', (data) => {
 | 
			
		||||
                logMessage(`achievement:received: ${JSON.stringify(data)}`, 'server');
 | 
			
		||||
            });
 | 
			
		||||
            socket.on('achievement:progress', (data) => {
 | 
			
		||||
                logMessage(`achievement:progress: ${JSON.stringify(data)}`, 'server');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            socket.on('connect_error', (err) => {
 | 
			
		||||
                logMessage(`Ошибка подключения: ${err.message}`, 'status');
 | 
			
		||||
                socket = null;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function sendMessage() {
 | 
			
		||||
            const message = messageInput.value;
 | 
			
		||||
            if (socket && message) {
 | 
			
		||||
                socket.emit('client_message', { data: message });
 | 
			
		||||
                logMessage(`Я: ${message}`, 'client');
 | 
			
		||||
                messageInput.value = '';
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        connectBtn.addEventListener('click', connectToServer);
 | 
			
		||||
        disconnectBtn.addEventListener('click', () => {
 | 
			
		||||
            if (socket) socket.disconnect();
 | 
			
		||||
        });
 | 
			
		||||
        sendBtn.addEventListener('click', sendMessage);
 | 
			
		||||
        messageInput.addEventListener('keyup', (event) => {
 | 
			
		||||
            if (event.key === 'Enter') {
 | 
			
		||||
                sendMessage();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        clearLogBtn.addEventListener('click', () => {
 | 
			
		||||
            messagesDiv.innerHTML = '';
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@ -6,6 +6,10 @@
 | 
			
		||||
	objectVersion = 77;
 | 
			
		||||
	objects = {
 | 
			
		||||
 | 
			
		||||
/* Begin PBXBuildFile section */
 | 
			
		||||
		1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */ = {isa = PBXBuildFile; productRef = 1A85C6CB2EA6FD73009FA847 /* SocketIO */; };
 | 
			
		||||
/* End PBXBuildFile section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXContainerItemProxy section */
 | 
			
		||||
		1A6D61DB2E7CD04000B9F736 /* PBXContainerItemProxy */ = {
 | 
			
		||||
			isa = PBXContainerItemProxy;
 | 
			
		||||
@ -52,6 +56,7 @@
 | 
			
		||||
			isa = PBXFrameworksBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
				1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
@ -112,6 +117,7 @@
 | 
			
		||||
			);
 | 
			
		||||
			name = yobble;
 | 
			
		||||
			packageProductDependencies = (
 | 
			
		||||
				1A85C6CB2EA6FD73009FA847 /* SocketIO */,
 | 
			
		||||
			);
 | 
			
		||||
			productName = yobble;
 | 
			
		||||
			productReference = 1A6D61CC2E7CD03E00B9F736 /* yobble.app */;
 | 
			
		||||
@ -196,6 +202,9 @@
 | 
			
		||||
			);
 | 
			
		||||
			mainGroup = 1A6D61C32E7CD03E00B9F736;
 | 
			
		||||
			minimizedProjectReferenceProxies = 1;
 | 
			
		||||
			packageReferences = (
 | 
			
		||||
				1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */,
 | 
			
		||||
			);
 | 
			
		||||
			preferredProjectObjectVersion = 77;
 | 
			
		||||
			productRefGroup = 1A6D61CD2E7CD03E00B9F736 /* Products */;
 | 
			
		||||
			projectDirPath = "";
 | 
			
		||||
@ -598,6 +607,25 @@
 | 
			
		||||
			defaultConfigurationName = Release;
 | 
			
		||||
		};
 | 
			
		||||
/* End XCConfigurationList section */
 | 
			
		||||
 | 
			
		||||
/* Begin XCRemoteSwiftPackageReference section */
 | 
			
		||||
		1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */ = {
 | 
			
		||||
			isa = XCRemoteSwiftPackageReference;
 | 
			
		||||
			repositoryURL = "https://github.com/socketio/socket.io-client-swift";
 | 
			
		||||
			requirement = {
 | 
			
		||||
				kind = exactVersion;
 | 
			
		||||
				version = 16.1.1;
 | 
			
		||||
			};
 | 
			
		||||
		};
 | 
			
		||||
/* End XCRemoteSwiftPackageReference section */
 | 
			
		||||
 | 
			
		||||
/* Begin XCSwiftPackageProductDependency section */
 | 
			
		||||
		1A85C6CB2EA6FD73009FA847 /* SocketIO */ = {
 | 
			
		||||
			isa = XCSwiftPackageProductDependency;
 | 
			
		||||
			package = 1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */;
 | 
			
		||||
			productName = SocketIO;
 | 
			
		||||
		};
 | 
			
		||||
/* End XCSwiftPackageProductDependency section */
 | 
			
		||||
	};
 | 
			
		||||
	rootObject = 1A6D61C42E7CD03E00B9F736 /* Project object */;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
{
 | 
			
		||||
  "originHash" : "c9fb241c5f575df8f20b39649006995779013948e60c51c3f85b729f83b054e7",
 | 
			
		||||
  "pins" : [
 | 
			
		||||
    {
 | 
			
		||||
      "identity" : "socket.io-client-swift",
 | 
			
		||||
      "kind" : "remoteSourceControl",
 | 
			
		||||
      "location" : "https://github.com/socketio/socket.io-client-swift",
 | 
			
		||||
      "state" : {
 | 
			
		||||
        "revision" : "42da871d9369f290d6ec4930636c40672143905b",
 | 
			
		||||
        "version" : "16.1.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "identity" : "starscream",
 | 
			
		||||
      "kind" : "remoteSourceControl",
 | 
			
		||||
      "location" : "https://github.com/daltoniam/Starscream",
 | 
			
		||||
      "state" : {
 | 
			
		||||
        "revision" : "c6bfd1af48efcc9a9ad203665db12375ba6b145a",
 | 
			
		||||
        "version" : "4.0.8"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "version" : 3
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								yobble/Network/AuthNotifications.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								yobble/Network/AuthNotifications.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
extension Notification.Name {
 | 
			
		||||
    static let accessTokenDidChange = Notification.Name("accessTokenDidChange")
 | 
			
		||||
}
 | 
			
		||||
@ -69,6 +69,8 @@ final class AuthService {
 | 
			
		||||
                    }
 | 
			
		||||
                    UserDefaults.standard.set(username, forKey: "currentUser")
 | 
			
		||||
 | 
			
		||||
                    NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
 | 
			
		||||
 | 
			
		||||
                    completion(true, nil)
 | 
			
		||||
                } catch {
 | 
			
		||||
                    completion(false, NSLocalizedString("Не удалось обработать ответ сервера.", comment: ""))
 | 
			
		||||
@ -175,6 +177,8 @@ final class AuthService {
 | 
			
		||||
 | 
			
		||||
        UserDefaults.standard.removeObject(forKey: "currentUser")
 | 
			
		||||
 | 
			
		||||
        NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
 | 
			
		||||
 | 
			
		||||
        let allUsers = KeychainService.shared.getAllServices()
 | 
			
		||||
        for user in allUsers {
 | 
			
		||||
            let hasAccessToken = KeychainService.shared.get(forKey: "access_token", service: user) != nil
 | 
			
		||||
@ -183,6 +187,7 @@ final class AuthService {
 | 
			
		||||
            if hasAccessToken && hasRefreshToken {
 | 
			
		||||
                UserDefaults.standard.set(user, forKey: "currentUser")
 | 
			
		||||
                if AppConfig.DEBUG { print("Logout: переключились на пользователя \(user)") }
 | 
			
		||||
                NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
 | 
			
		||||
                completion(true, nil)
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -266,6 +266,8 @@ final class NetworkClient {
 | 
			
		||||
                            KeychainService.shared.save(userId, forKey: "userId", service: tokenInfo.login)
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        NotificationCenter.default.post(name: .accessTokenDidChange, object: nil)
 | 
			
		||||
 | 
			
		||||
                        self.completeRefresh(success: true)
 | 
			
		||||
                    } catch {
 | 
			
		||||
                        self.completeRefresh(success: false)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										135
									
								
								yobble/Services/SocketService.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								yobble/Services/SocketService.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,135 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
#if canImport(SocketIO)
 | 
			
		||||
import SocketIO
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
final class SocketService {
 | 
			
		||||
    static let shared = SocketService()
 | 
			
		||||
 | 
			
		||||
    private let syncQueue = DispatchQueue(label: "org.yobble.socket.service")
 | 
			
		||||
    private var currentToken: String?
 | 
			
		||||
    private var currentAuthPayload: [String: Any] = [:]
 | 
			
		||||
 | 
			
		||||
    #if canImport(SocketIO)
 | 
			
		||||
    private var manager: SocketManager?
 | 
			
		||||
    private var socket: SocketIOClient?
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    private init() {}
 | 
			
		||||
 | 
			
		||||
    func connectForCurrentUser() {
 | 
			
		||||
        syncQueue.async { [weak self] in
 | 
			
		||||
            guard let self else { return }
 | 
			
		||||
            guard let token = self.resolveCurrentAccessToken() else {
 | 
			
		||||
                if AppConfig.DEBUG { print("[SocketService] No access token available, disconnecting") }
 | 
			
		||||
                self.currentToken = nil
 | 
			
		||||
                self.disconnectInternal()
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            self.connectInternal(with: token)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func connect(withToken token: String) {
 | 
			
		||||
        syncQueue.async { [weak self] in
 | 
			
		||||
            self?.connectInternal(with: token)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func disconnect() {
 | 
			
		||||
        syncQueue.async { [weak self] in
 | 
			
		||||
            guard let self else { return }
 | 
			
		||||
            self.currentToken = nil
 | 
			
		||||
            self.disconnectInternal()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func resolveCurrentAccessToken() -> String? {
 | 
			
		||||
        guard
 | 
			
		||||
            let login = UserDefaults.standard.string(forKey: "currentUser"),
 | 
			
		||||
            !login.isEmpty
 | 
			
		||||
        else {
 | 
			
		||||
            return nil
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return KeychainService.shared.get(forKey: "access_token", service: login)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func connectInternal(with token: String) {
 | 
			
		||||
        #if canImport(SocketIO)
 | 
			
		||||
        if token == currentToken,
 | 
			
		||||
           let socket,
 | 
			
		||||
           socket.status == .connected || socket.status == .connecting {
 | 
			
		||||
            if AppConfig.DEBUG { print("[SocketService] Already connected with current token") }
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        currentToken = token
 | 
			
		||||
        currentAuthPayload = ["token": token]
 | 
			
		||||
        setupSocket(with: token)
 | 
			
		||||
        socket?.connect(withPayload: currentAuthPayload)
 | 
			
		||||
        #else
 | 
			
		||||
        if AppConfig.DEBUG {
 | 
			
		||||
            print("[SocketService] SocketIO framework not available; skipping connection")
 | 
			
		||||
        }
 | 
			
		||||
        #endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #if canImport(SocketIO)
 | 
			
		||||
    private func setupSocket(with token: String) {
 | 
			
		||||
        guard let baseURL = URL(string: AppConfig.API_SERVER) else {
 | 
			
		||||
            if AppConfig.DEBUG { print("[SocketService] Invalid socket URL: \(AppConfig.API_SERVER)") }
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        disconnectInternal()
 | 
			
		||||
 | 
			
		||||
        let configuration: SocketIOClientConfiguration = [
 | 
			
		||||
            .log(AppConfig.DEBUG),
 | 
			
		||||
            .compress,
 | 
			
		||||
            .secure(AppConfig.PROTOCOL.lowercased() == "https"),
 | 
			
		||||
            .path(AppConfig.SOCKET_PATH),
 | 
			
		||||
            .reconnects(true),
 | 
			
		||||
            .reconnectWait(2),
 | 
			
		||||
            .forceWebsockets(true),
 | 
			
		||||
            .extraHeaders(["Authorization": "Bearer \(token)"]),
 | 
			
		||||
            .connectParams(["token": token])
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        let manager = SocketManager(socketURL: baseURL, config: configuration)
 | 
			
		||||
        manager.handleQueue = syncQueue
 | 
			
		||||
        let socket = manager.defaultSocket
 | 
			
		||||
 | 
			
		||||
        if AppConfig.DEBUG {
 | 
			
		||||
            socket.onAny { event in
 | 
			
		||||
                print("[SocketService] onAny event=\(event.event) data=\(event.items ?? [])")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        socket.on(clientEvent: .connect) { _, _ in
 | 
			
		||||
            if AppConfig.DEBUG { print("[SocketService] Connected") }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        socket.on(clientEvent: .disconnect) { data, _ in
 | 
			
		||||
            if AppConfig.DEBUG { print("[SocketService] Disconnected: \(data)") }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        socket.on(clientEvent: .error) { data, _ in
 | 
			
		||||
            if AppConfig.DEBUG { print("[SocketService] Error: \(data)") }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.manager = manager
 | 
			
		||||
        self.socket = socket
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func disconnectInternal() {
 | 
			
		||||
        socket?.disconnect()
 | 
			
		||||
        manager?.disconnect()
 | 
			
		||||
        socket = nil
 | 
			
		||||
        manager = nil
 | 
			
		||||
    }
 | 
			
		||||
    #else
 | 
			
		||||
    private func disconnectInternal() { }
 | 
			
		||||
    #endif
 | 
			
		||||
}
 | 
			
		||||
@ -18,6 +18,7 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
    @Published var isLoggedIn: Bool = false
 | 
			
		||||
 | 
			
		||||
    private let authService = AuthService()
 | 
			
		||||
    private let socketService = SocketService.shared
 | 
			
		||||
 | 
			
		||||
    private enum DefaultsKeys {
 | 
			
		||||
        static let currentUser = "currentUser"
 | 
			
		||||
@ -38,10 +39,12 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
                if success {
 | 
			
		||||
                    self?.loadStoredUser()
 | 
			
		||||
                    self?.isLoggedIn = true
 | 
			
		||||
                    self?.socketService.connectForCurrentUser()
 | 
			
		||||
                } else {
 | 
			
		||||
                    self?.isLoggedIn = false
 | 
			
		||||
                    self?.errorMessage = error ?? NSLocalizedString("Произошла ошибка.", comment: "")
 | 
			
		||||
                    self?.showError = false
 | 
			
		||||
                    self?.socketService.disconnect()
 | 
			
		||||
                }
 | 
			
		||||
                self?.isLoading = false
 | 
			
		||||
            }
 | 
			
		||||
@ -59,9 +62,11 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
                if success {
 | 
			
		||||
                    self?.loadStoredUser()
 | 
			
		||||
                    self?.isLoggedIn = true
 | 
			
		||||
                    self?.socketService.connectForCurrentUser()
 | 
			
		||||
                } else {
 | 
			
		||||
                    self?.errorMessage = error ?? NSLocalizedString("Неизвестная ошибка", comment: "")
 | 
			
		||||
                    self?.showError = true
 | 
			
		||||
                    self?.socketService.disconnect()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -73,6 +78,9 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
                if success {
 | 
			
		||||
                    self?.isLoggedIn = true // 👈 переключаем на главный экран после автологина
 | 
			
		||||
                    self?.loadStoredUser()
 | 
			
		||||
                    self?.socketService.connectForCurrentUser()
 | 
			
		||||
                } else {
 | 
			
		||||
                    self?.socketService.disconnect()
 | 
			
		||||
                }
 | 
			
		||||
                completion(success, message)
 | 
			
		||||
            }
 | 
			
		||||
@ -87,6 +95,7 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
                    self?.password = ""
 | 
			
		||||
                    self?.isLoggedIn = true
 | 
			
		||||
                    self?.showError = false
 | 
			
		||||
                    self?.socketService.connectForCurrentUser()
 | 
			
		||||
                } else {
 | 
			
		||||
                    self?.username = ""
 | 
			
		||||
                    self?.userId = ""
 | 
			
		||||
@ -94,6 +103,7 @@ class LoginViewModel: ObservableObject {
 | 
			
		||||
                    self?.isLoggedIn = false
 | 
			
		||||
                    self?.errorMessage = error ?? NSLocalizedString("Ошибка при деавторизации.", comment: "")
 | 
			
		||||
                    self?.showError = false
 | 
			
		||||
                    self?.socketService.disconnect()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ struct AppConfig {
 | 
			
		||||
    //static let SERVICE = Bundle.main.bundleIdentifier ?? "default.service"
 | 
			
		||||
    static let PROTOCOL = "https"
 | 
			
		||||
    static let API_SERVER = "\(PROTOCOL)://api.yobble.org"
 | 
			
		||||
    static let SOCKET_PATH = "/socket.io/"
 | 
			
		||||
 | 
			
		||||
    static let USER_AGENT = "yobble ios"
 | 
			
		||||
    static let APP_BUILD = "appstore" // appstore / freestore
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user