I’m making an attempt to make use of the newest model of Swift package deal socket.io-client-swift to hook up with my socket.io server inbuilt Node.js, however no connection ever appears to be made, as a result of nothing is logged within the console indicating {that a} connection was efficiently made – no polling, no established handshake.
These are the logs that happen within the app indicating {that a} connection can’t be established:
LOG SocketIOClient{/}: Including handler for occasion: join
LOG SocketIOClient{/}: Including handler for occasion: disconnect
LOG SocketIOClient{/}: Including handler for occasion: error
LOG SocketIOClient{/}: Dealing with occasion: statusChange with information: [connecting, 2]
LOG SocketIOClient{/}: Becoming a member of namespace /
LOG SocketManager: Tried connecting socket when engine is not open. Connecting
LOG SocketManager: Including engine
LOG SocketEngine: Beginning engine. Server: https://ws.my-socket-server.com
LOG SocketEngine: Handshaking
LOG SocketManager: Supervisor is being launched
LOG SocketIOClient{/}: Including handler for occasion: join
LOG SocketIOClient{/}: Including handler for occasion: disconnect
LOG SocketIOClient{/}: Including handler for occasion: error
LOG SocketIOClient{/}: Dealing with occasion: statusChange with information: [connecting, 2]
LOG SocketIOClient{/}: Becoming a member of namespace /
LOG SocketManager: Tried connecting socket when engine is not open. Connecting
LOG SocketManager: Tried connecting an already lively socket
As you possibly can see, it says “Tried connecting socket when engine is not open” & releases the Supervisor very early.
Right here is my singleton WebSocketManager I’m creating to share the socket with all of my views:
import Basis
import SocketIO
class WebSocketManager: NSObject, ObservableObject, URLSessionWebSocketDelegate {
static let shared = WebSocketManager()
@Revealed var drawingSocket: SocketIOClient?
personal var drawingSocketManager: SocketManager?
personal let drawingSocketURL = URL(string: "https://ws.my-socket-server.com")!
override personal init() {
tremendous.init()
setupDrawingSocket()
}
personal func setupDrawingSocket() {
drawingSocketManager = SocketManager(socketURL: drawingSocketURL, config: [.log(true), .reconnectAttempts(5), .reconnectWaitMax(5), .forceWebsockets(true)])
drawingSocket = drawingSocketManager?.defaultSocket
drawingSocket?.on(clientEvent: .join) { _, _ in
print("Drawing socket related")
}
drawingSocket?.on(clientEvent: .disconnect) { information, _ in
print("Drawing socket disconnected: (information)")
}
drawingSocket?.on(clientEvent: .error) { information, _ in
print("Drawing socket error: (information)")
}
if drawingSocket?.standing != .related {
drawingSocket?.join()
}
}
func sendDrawingMessage(_ motion: String, information: Any) {
guard let drawingSocket = drawingSocket else {
print("Drawing socket isn't obtainable")
return
}
// Examine if the socket is related earlier than sending a message
if drawingSocket.standing == .related {
drawingSocket.emit(motion, information as! SocketData)
} else {
print("Drawing socket isn't related. Can't ship message.")
}
}
var isDrawingSocketConnected: Bool {
return drawingSocket?.standing == .related
}
}
Right here is the entrypoint to all of my views:
import SwiftUI
@fundamental
struct my_iosApp: App {
var physique: some Scene {
WindowGroup {
Residence()
.environmentObject(WebSocketManager.shared)
.environmentObject(GlobalStateManager.shared)
}
}
}
and eventually, right here is the place I’m utilizing the socket to emit a message to the server:
import SocketIO
import SwiftUI
struct GameCodeDisplay: View {
@EnvironmentObject var globalStateManager: GlobalStateManager
@EnvironmentObject var webSocketManager: WebSocketManager
let gameCode: String
var onCancel: () -> Void
personal var drawingSocket: SocketIOClient
init(gameCode: String, onCancel: @escaping () -> Void) {
self.gameCode = gameCode
self.onCancel = onCancel
let supervisor = SocketManager(socketURL: URL(string: "https://ws.my-socket-server.com")!, config: [.log(true), .reconnectAttempts(5), .reconnectWaitMax(5), .forceWebsockets(true)])
self.drawingSocket = supervisor.defaultSocket
}
var physique: some View {
ZStack {
Coloration(crimson: 115.0 / 255.0, inexperienced: 5.0 / 255.0, blue: 60.0 / 255.0)
.edgesIgnoringSafeArea(.all)
VStack {
Spacer() // Pushes content material to the middle
Textual content("Your recreation code is:")
.font(.title)
.fontWeight(.daring)
.foregroundColor(.white)
Textual content(gameCode)
.font(.largeTitle)
.fontWeight(.daring)
.foregroundColor(.white)
.padding(.backside)
ScrollView {
VStack {
ForEach(globalStateManager.gamers, id: .self) { participant in
Textual content(participant)
.body(maxWidth: .infinity)
.multilineTextAlignment(.heart)
.foregroundColor(.white)
}
}
}
.body(maxHeight: 200) // Modify as wanted
if globalStateManager.gamers.depend >= 5 {
Button("Begin!") {
startGame(drawingSocket: drawingSocket, gameCode: gameCode)
}
.disabled(globalStateManager.gamers.depend < 5)
.padding()
.foregroundColor(.inexperienced)
}
Button("Cancel") {
onCancel()
leaveGame(webSocketManager: webSocketManager, globalStateManager: globalStateManager)
}
.padding()
.foregroundColor(.yellow)
Spacer() // Permits the button to be on the backside
}
.body(maxWidth: .infinity, maxHeight: .infinity)
.padding() // Add padding across the complete VStack
}.onAppear {
setupDrawingSocketEvents()
}
}
personal func setupDrawingSocketEvents() {
guard let drawingSocket = webSocketManager.drawingSocket else {
print("Drawing socket not obtainable")
return
}
drawingSocket.on(clientEvent: .join) { _, _ in
print("Drawing socket related")
// Further code for when the socket connects
}
drawingSocket.on(clientEvent: .disconnect) { information, _ in
print("Drawing socket disconnected: (information)")
// Further code for when the socket disconnects
}
drawingSocket.on(clientEvent: .error) { information, _ in
print("Drawing socket error: (information)")
// Further error dealing with
}
// Hook up with the socket if not related
if !webSocketManager.isDrawingSocketConnected {
drawingSocket.join()
}
}
personal func startGame(drawingSocket: SocketIOClient, gameCode: String) {
print("GameCodeDisplay: Beginning recreation with gameCode - (gameCode)")
webSocketManager.sendDrawingMessage("joinGame", information: gameCode)
webSocketManager.sendDrawingMessage("startGame", information: gameCode)
}
personal func leaveGame(webSocketManager: WebSocketManager, globalStateManager: GlobalStateManager) {
print("GameCodeDisplay: Leaving recreation with gameCode - (gameCode)")
webSocketManager.sendLeaveGameMessage(gameCode: gameCode, username: globalStateManager.username)
webSocketManager.disconnect()
globalStateManager.gamers.removeAll()
globalStateManager.setUsername(usernameToSet: "")
}
}
Right here is Node.js server that the socket is operating on. I’m utilizing model socket.io: “^4.7.2”:
const categorical = require("categorical");
const { Server } = require("socket.io");
const cors = require("cors");
const http = require("http");
const allowedOrigins = [
"https://website-1.com",
"https://website-2.com",
"http://localhost:3000",
];
const app = categorical();
app.use(
cors({
origin: perform (origin, callback) {
console.log("origin: ", origin);
if (!origin) return callback(null, true); // Enable requests with no origin (like cell apps or curl requests)
if (allowedOrigins.indexOf(origin) === -1) {
const msg =
"The CORS coverage for this web site doesn't permit entry from the desired Origin.";
return callback(new Error(msg), false);
}
return callback(null, true);
},
})
);
app.get("/health-check", (req, res) => res.standing(200).ship("OK"));
const server = http.createServer(app);
const io = new Server(server, {
transports: ["websocket"],
cors: {
origin: perform (origin, callback) {
if (allowedOrigins.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
strategies: ["GET", "POST"],
},
});
const connectedSockets = new Set();
io.on("connection", (socket) => {
connectedSockets.add(socket);
socket.on("joinGame", (gameCode, callback) => {
socket.be part of(gameCode);
console.log(`Socket with ID ${socket.id} joined room: ${gameCode}`);
if (typeof callback === "perform") {
callback(`Joined room: ${gameCode}`);
}
});
socket.on("startGame", (gameCode) => {
console.log("Emitting gameStarted to room:", gameCode);
io.to(gameCode).emit("gameStarted");
});
});
server.hear(3001, (err) => {
connectedSockets.forEach((socket) => {
socket.disconnect(true);
});
connectedSockets.clear();
if (err) throw err;
console.log("> Prepared on http://localhost:3001");
});
I’ve tried a wide range of alternative ways of making that singleton I discussed of the WebSocketManager to no avail. At this level, I’m open to another Swift package deal options to hook up with my socket.io server from my SwiftUI iOS app.