extends Control
# extends "res://src/ResizeRoot.gd"
# Messages are JSON which contain {id, from, username, type, content}
# All messages have a username and type
# Some messages contain a `from` for peer that sent the message
# If no `from` field is visible, it means it's from the sending peer
# type: 'text` will have `content` of the text message that got sent
# type: 'identity' will have empty `content`, and is there to notify peers of this users existence
# GET peer list to start registering for extensions
# Set up list of seen remotePublicKeys
# Broadcast self after a second of waiting for peers
# Broadcast self on name change
# Broadcast self when seeing a new remotePublicKey
@export var archiveRoot = 'hyper://blog.mauve.moe/'
#export var archiveRoot = 'hyper://70338a94d7415990ab4a3160cf98a5d940243d7fa24dd297352e66b52d3ff841/'
@export var extensionName = 'hyperchat-example-1'
const LRU = preload('res://hypergodot/utils/lru.gd')
@onready var jsonInstance = JSON.new()
var extensionsFolder = archiveRoot + '$/extensions/'
var extensionPath = extensionsFolder + extensionName
var seen_messages = LRU.new()
var seen_identities = LRU.new()
@onready var eventSource = $HyperGateway/HyperEventSource
@onready var gateway = $HyperGateway
@onready var chatBox = $ScrollContainer/ChatBox
@onready var chatText = $HBoxContainer/ChatInput
@onready var username = $HBoxContainer/Username
@onready var broadcastRequest = $HyperGateway/BroadcastRequest
@onready var listPeersRequest = $HyperGateway/ListPeersRequest
func _ready():
# Initialize random number generator
randomize()
gateway.start()
func display_item(from, content):
# Add to item list
chatBox.text += from + ': ' + content + "\n"
func send_current():
var text = chatText.text
chatText.text = ""
display_item(get_username(), text)
broadcast_text(text)
func update_identity(_from, _username):
# Have some sort of sidebar to display known users?
display_item('System', 'Seen user ' + _username)
pass
func list_peers():
listPeersRequest.request(extensionPath)
func _on_text_message(data, _from):
# TODO: Something fancy with the `from` attribute?
display_item(data.username, data.content)
func _on_identity_message(_data, from):
var isNew = !has_seen_identity(from)
# Track identity
seen_identities.track(from)
# If it's new, broadcast your own identity
if isNew:
broadcast_identity()
func _on_unknown_message(data, from):
# Emit some sort of error?
printerr("Got unknown message", from, data)
func get_username():
return username.text
func broadcast_text(content):
var _username = get_username()
broadcast_message({
'type': 'text',
'content': content,
'username': _username
})
func broadcast_identity():
var _username = get_username()
broadcast_message({
'type': 'identity',
'username': _username
})
func broadcast_message(message):
# POST to extension URL
if !("id" in message):
message.id = make_id()
seen_messages.track(message.id)
print('Broadcasting message', message, extensionPath)
var body = jsonInstance.stringify(message)
broadcastRequest.request(extensionPath,[], false, HTTPClient.METHOD_POST, body)
func has_seen_identity(from):
return seen_identities.has(from)
func has_seen_message(id):
return seen_messages.has(id)
func re_broadcast(message, from):
if !("from" in message):
message.from = from
broadcast_message(message)
func handle_message(message, from):
var finalFrom = message.from if "from" in message else from
if !("id" in message):
return _on_unknown_message(message, finalFrom)
if has_seen_message(message.id):
return
re_broadcast(message, finalFrom)
match message.type:
'text':
_on_text_message(message, finalFrom)
'identity':
_on_identity_message(message, finalFrom)
_:
_on_unknown_message(message, finalFrom)
func _on_event(data, _event, id):
var jsonLocal = JSON.new()
var error = jsonLocal.parse(data)
var parsed = null
if error != OK:
printerr("Unable to parse EventSource content " + jsonLocal.get_error_line() + "\n" + data)
else:
parsed = jsonLocal.get_data()
handle_message(parsed.result, id)
func make_id():
return str(randi()) + str(randi())
func start_listening():
eventSource.request(extensionsFolder)
func _on_ChatInput_text_entered(_new_text):
send_current()
pass # Replace with function body.
func _on_send_button_pressed():
send_current()
func _on_hyper_event_source_event(data, event, id):
_on_event(data, event, id)
func _on_hyper_gateway_started_gateway(pid):
start_listening()
list_peers()
broadcast_identity()