ws_webrtc_client.gd 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. extends Node
  2. enum Message {
  3. JOIN,
  4. ID,
  5. PEER_CONNECT,
  6. PEER_DISCONNECT,
  7. OFFER,
  8. ANSWER,
  9. CANDIDATE,
  10. SEAL,
  11. }
  12. @export var autojoin := true
  13. @export var lobby := "" # Will create a new lobby if empty.
  14. @export var mesh := true # Will use the lobby host as relay otherwise.
  15. var ws := WebSocketPeer.new()
  16. var code := 1000
  17. var reason := "Unknown"
  18. var old_state := WebSocketPeer.STATE_CLOSED
  19. signal lobby_joined(lobby: String)
  20. signal connected(id: int, use_mesh: bool)
  21. signal disconnected()
  22. signal peer_connected(id: int)
  23. signal peer_disconnected(id: int)
  24. signal offer_received(id: int, offer: String)
  25. signal answer_received(id: int, answer: String)
  26. signal candidate_received(id: int, mid: String, index: int, sdp: String)
  27. signal lobby_sealed()
  28. func connect_to_url(url: String) -> void:
  29. close()
  30. code = 1000
  31. reason = "Unknown"
  32. ws.connect_to_url(url)
  33. func close() -> void:
  34. ws.close()
  35. func _process(_delta: float) -> void:
  36. ws.poll()
  37. var state := ws.get_ready_state()
  38. if state != old_state and state == WebSocketPeer.STATE_OPEN and autojoin:
  39. join_lobby(lobby)
  40. while state == WebSocketPeer.STATE_OPEN and ws.get_available_packet_count():
  41. if not _parse_msg():
  42. print("Error parsing message from server.")
  43. if state != old_state and state == WebSocketPeer.STATE_CLOSED:
  44. code = ws.get_close_code()
  45. reason = ws.get_close_reason()
  46. disconnected.emit()
  47. old_state = state
  48. func _parse_msg() -> bool:
  49. var parsed: Dictionary = JSON.parse_string(ws.get_packet().get_string_from_utf8())
  50. if typeof(parsed) != TYPE_DICTIONARY or not parsed.has("type") or not parsed.has("id") or \
  51. typeof(parsed.get("data")) != TYPE_STRING:
  52. return false
  53. var msg := parsed as Dictionary
  54. if not str(msg.type).is_valid_int() or not str(msg.id).is_valid_int():
  55. return false
  56. var type := str(msg.type).to_int()
  57. var src_id := str(msg.id).to_int()
  58. if type == Message.ID:
  59. connected.emit(src_id, msg.data == "true")
  60. elif type == Message.JOIN:
  61. lobby_joined.emit(msg.data)
  62. elif type == Message.SEAL:
  63. lobby_sealed.emit()
  64. elif type == Message.PEER_CONNECT:
  65. # Client connected.
  66. peer_connected.emit(src_id)
  67. elif type == Message.PEER_DISCONNECT:
  68. # Client connected.
  69. peer_disconnected.emit(src_id)
  70. elif type == Message.OFFER:
  71. # Offer received.
  72. offer_received.emit(src_id, msg.data)
  73. elif type == Message.ANSWER:
  74. # Answer received.
  75. answer_received.emit(src_id, msg.data)
  76. elif type == Message.CANDIDATE:
  77. # Candidate received.
  78. var candidate: PackedStringArray = msg.data.split("\n", false)
  79. if candidate.size() != 3:
  80. return false
  81. if not candidate[1].is_valid_int():
  82. return false
  83. candidate_received.emit(src_id, candidate[0], candidate[1].to_int(), candidate[2])
  84. else:
  85. return false
  86. return true # Parsed.
  87. func join_lobby(lobby: String) -> Error:
  88. return _send_msg(Message.JOIN, 0 if mesh else 1, lobby)
  89. func seal_lobby() -> Error:
  90. return _send_msg(Message.SEAL, 0)
  91. func send_candidate(id: int, mid: String, index: int, sdp: String) -> Error:
  92. return _send_msg(Message.CANDIDATE, id, "\n%s\n%d\n%s" % [mid, index, sdp])
  93. func send_offer(id: int, offer: String) -> Error:
  94. return _send_msg(Message.OFFER, id, offer)
  95. func send_answer(id: int, answer: String) -> Error:
  96. return _send_msg(Message.ANSWER, id, answer)
  97. func _send_msg(type: int, id: int, data: String = "") -> Error:
  98. return ws.send_text(JSON.stringify({
  99. "type": type,
  100. "id": id,
  101. "data": data,
  102. }))