ws_webrtc_client.gd 3.1 KB

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