OverviewFilesCommitsIssuesDocsReleasesPeers

hypergodot / src / HyperChat / HyperChat.gd

161 lines · gd ref:
extends "res://src/ResizeRoot.gd"

const LRU = preload('res://src/utils/LRU.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'

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 = JSON.print(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 parsed = JSON.parse(data)
	
	if parsed.error != OK:
		printerr("Unable to parse EventSource content " + parsed.error_line + "\n" + data)
		return
	
	handle_message(parsed.result, id)

func make_id():
	return str(randi()) + str(randi())

func start_listening():
	eventSource.request(extensionsFolder)	

func _on_HyperEventSource_event(data, event, id):
	_on_event(data, event, id)

func _on_HyperGateway_started_gateway(_pid):
	start_listening()
	list_peers()
	broadcast_identity()

func _on_SendButton_pressed():
	send_current()
	pass # Replace with function body.

func _on_ChatInput_text_entered(_new_text):
	send_current()
	pass # Replace with function body.