ws_webrtc_client.gd 3.1 KB

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