Skip to content

Commit

Permalink
Cloud Storage API (#88)
Browse files Browse the repository at this point in the history
* Started work on the Cloud storage api

* Moved Storage networking to internal_process loop.

* Implemented the rest of Storage API,
Implemented authentication support,
Added MIME Type constants in StorageRef.

* Added `get_string()` to `StorageReference`,
Made some `StorageTask` properties private.

* Removed redundant constant

The HTTPSSEClient constant was no longer needed.
  • Loading branch information
SIsilicon authored Jan 31, 2021
1 parent 44ed2f8 commit cdbaf7d
Show file tree
Hide file tree
Showing 13 changed files with 1,077 additions and 643 deletions.
356 changes: 178 additions & 178 deletions addons/godot-firebase/auth/auth.gd

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions addons/godot-firebase/database/database.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ var config : Dictionary = {}
var auth : Dictionary = {}

func set_config(config_json : Dictionary) -> void:
config = config_json
config = config_json

func _on_FirebaseAuth_login_succeeded(auth_result : Dictionary) -> void:
auth = auth_result
auth = auth_result

func get_database_reference(path : String, filter : Dictionary = {}) -> FirebaseDatabaseReference:
var firebase_reference : FirebaseDatabaseReference = FirebaseDatabaseReference.new()
var pusher : HTTPRequest = HTTPRequest.new()
var listener : Node = Node.new()
listener.set_script(load("res://addons/http-sse-client/HTTPSSEClient.gd"))
var store : FirebaseDatabaseStore = FirebaseDatabaseStore.new()
firebase_reference.set_db_path(path, filter)
firebase_reference.set_auth_and_config(auth, config)
firebase_reference.set_pusher(pusher)
firebase_reference.set_listener(listener)
firebase_reference.set_store(store)
add_child(firebase_reference)
return firebase_reference
var firebase_reference : FirebaseDatabaseReference = FirebaseDatabaseReference.new()
var pusher : HTTPRequest = HTTPRequest.new()
var listener : Node = Node.new()
listener.set_script(load("res://addons/http-sse-client/HTTPSSEClient.gd"))
var store : FirebaseDatabaseStore = FirebaseDatabaseStore.new()
firebase_reference.set_db_path(path, filter)
firebase_reference.set_auth_and_config(auth, config)
firebase_reference.set_pusher(pusher)
firebase_reference.set_listener(listener)
firebase_reference.set_store(store)
add_child(firebase_reference)
return firebase_reference
166 changes: 83 additions & 83 deletions addons/godot-firebase/database/reference.gd
Original file line number Diff line number Diff line change
Expand Up @@ -33,120 +33,120 @@ const _equal_tag : String = "="
const _key_filter_tag : String = "$key"

func set_db_path(path : String, filter_query_dict : Dictionary) -> void:
_db_path = path
_filter_query = filter_query_dict
_db_path = path
_filter_query = filter_query_dict

func set_auth_and_config(auth_ref : Dictionary, config_ref : Dictionary) -> void:
_auth = auth_ref
_config = config_ref
_auth = auth_ref
_config = config_ref

func set_pusher(pusher_ref : HTTPRequest) -> void:
if !_pusher:
_pusher = pusher_ref
add_child(_pusher)
_pusher.connect("request_completed", self, "on_push_request_complete")
if !_pusher:
_pusher = pusher_ref
add_child(_pusher)
_pusher.connect("request_completed", self, "on_push_request_complete")

func set_listener(listener_ref : Node) -> void:
if !_listener:
_listener = listener_ref
add_child(_listener)
_listener.connect("new_sse_event", self, "on_new_sse_event")
var base_url = _get_list_url().trim_suffix(_separator)
var extended_url = _separator + _db_path + _get_remaining_path(false)
_listener.connect_to_host(base_url, extended_url)
if !_listener:
_listener = listener_ref
add_child(_listener)
_listener.connect("new_sse_event", self, "on_new_sse_event")
var base_url = _get_list_url().trim_suffix(_separator)
var extended_url = _separator + _db_path + _get_remaining_path(false)
_listener.connect_to_host(base_url, extended_url)

func on_new_sse_event(headers : Dictionary, event : String, data : Dictionary) -> void:
if data:
var command = event
if command and command != "keep-alive":
_route_data(command, data.path, data.data)
if command == _put_tag:
if data.path == _separator and data.data and data.data.keys().size() > 0:
for key in data.data.keys():
emit_signal("new_data_update", FirebaseResource.new(_separator + key, data.data[key]))
elif data.path != _separator:
emit_signal("new_data_update", FirebaseResource.new(data.path, data.data))
elif command == _patch_tag:
emit_signal("patch_data_update", FirebaseResource.new(data.path, data.data))
pass
if data:
var command = event
if command and command != "keep-alive":
_route_data(command, data.path, data.data)
if command == _put_tag:
if data.path == _separator and data.data and data.data.keys().size() > 0:
for key in data.data.keys():
emit_signal("new_data_update", FirebaseResource.new(_separator + key, data.data[key]))
elif data.path != _separator:
emit_signal("new_data_update", FirebaseResource.new(data.path, data.data))
elif command == _patch_tag:
emit_signal("patch_data_update", FirebaseResource.new(data.path, data.data))
pass

func set_store(store_ref : FirebaseDatabaseStore) -> void:
if !_store:
_store = store_ref
add_child(_store)
if !_store:
_store = store_ref
add_child(_store)

func update(path : String, data : Dictionary) -> void:
path = path.strip_edges(true, true)

if path == _separator:
path = ""
var to_update = JSON.print(data)
if _pusher.get_http_client_status() != HTTPClient.STATUS_REQUESTING:
var resolved_path = (_get_list_url() + _db_path + "/" + path + _get_remaining_path())
_pusher.request(resolved_path, PoolStringArray(), true, HTTPClient.METHOD_PATCH, to_update)
else:
_push_queue.append(data)
path = path.strip_edges(true, true)

if path == _separator:
path = ""
var to_update = JSON.print(data)
if _pusher.get_http_client_status() != HTTPClient.STATUS_REQUESTING:
var resolved_path = (_get_list_url() + _db_path + "/" + path + _get_remaining_path())
_pusher.request(resolved_path, PoolStringArray(), true, HTTPClient.METHOD_PATCH, to_update)
else:
_push_queue.append(data)

func push(data : Dictionary) -> void:
var to_push = JSON.print(data)
if _pusher.get_http_client_status() == HTTPClient.STATUS_DISCONNECTED:
_pusher.request(_get_list_url() + _db_path + _get_remaining_path(), PoolStringArray(), true, HTTPClient.METHOD_POST, to_push)
else:
_push_queue.append(data)
var to_push = JSON.print(data)
if _pusher.get_http_client_status() == HTTPClient.STATUS_DISCONNECTED:
_pusher.request(_get_list_url() + _db_path + _get_remaining_path(), PoolStringArray(), true, HTTPClient.METHOD_POST, to_push)
else:
_push_queue.append(data)

#
# Returns a deep copy of the current local copy of the data stored at this reference in the Firebase
# Realtime Database.
#
func get_data() -> Dictionary:
if _store == null:
return { }
return _store.get_data()
if _store == null:
return { }
return _store.get_data()

func _get_remaining_path(is_push : bool = true) -> String:
if !_filter_query or is_push:
return _json_list_tag + _query_tag + _auth_tag + Firebase.Auth.auth.idtoken
else:
return _json_list_tag + _query_tag + _get_filter() + _filter_tag + _auth_tag + Firebase.Auth.auth.idtoken
if !_filter_query or is_push:
return _json_list_tag + _query_tag + _auth_tag + Firebase.Auth.auth.idtoken
else:
return _json_list_tag + _query_tag + _get_filter() + _filter_tag + _auth_tag + Firebase.Auth.auth.idtoken

func _get_list_url() -> String:
return _config.databaseURL + _separator # + ListName + _json_list_tag + _auth_tag + _auth.idtoken
return _config.databaseURL + _separator # + ListName + _json_list_tag + _auth_tag + _auth.idtoken

func _get_filter():
if !_filter_query:
return ""
# At the moment, this means you can't dynamically change your filter; I think it's okay to specify that in the rules.
if !_cached_filter:
_cached_filter = ""
if _filter_query.has(Firebase.Database.ORDER_BY):
_cached_filter += Firebase.Database.ORDER_BY + _equal_tag + _escaped_quote + _filter_query[Firebase.Database.ORDER_BY] + _escaped_quote
_filter_query.erase(Firebase.Database.ORDER_BY)
else:
_cached_filter += Firebase.Database.ORDER_BY + _equal_tag + _escaped_quote + _key_filter_tag + _escaped_quote # Presumptuous, but to get it to work at all...

for key in _filter_query.keys():
_cached_filter += _filter_tag + key + _equal_tag + _filter_query[key]

return _cached_filter
if !_filter_query:
return ""
# At the moment, this means you can't dynamically change your filter; I think it's okay to specify that in the rules.
if !_cached_filter:
_cached_filter = ""
if _filter_query.has(Firebase.Database.ORDER_BY):
_cached_filter += Firebase.Database.ORDER_BY + _equal_tag + _escaped_quote + _filter_query[Firebase.Database.ORDER_BY] + _escaped_quote
_filter_query.erase(Firebase.Database.ORDER_BY)
else:
_cached_filter += Firebase.Database.ORDER_BY + _equal_tag + _escaped_quote + _key_filter_tag + _escaped_quote # Presumptuous, but to get it to work at all...

for key in _filter_query.keys():
_cached_filter += _filter_tag + key + _equal_tag + _filter_query[key]

return _cached_filter

#
# Appropriately updates the current local copy of the data stored at this reference in the Firebase
# Realtime Database.
#
func _route_data(command : String, path : String, data) -> void:
if command == _put_tag:
_store.put(path, data)
elif command == _patch_tag:
_store.patch(path, data)
if command == _put_tag:
_store.put(path, data)
elif command == _patch_tag:
_store.patch(path, data)

func on_push_request_complete(result : int, response_code : int, headers : PoolStringArray, body : PoolByteArray) -> void:
if response_code == HTTPClient.RESPONSE_OK:
emit_signal("push_successful")
else:
emit_signal("push_failed")
if _push_queue.size() > 0:
push(_push_queue.pop_front())
if response_code == HTTPClient.RESPONSE_OK:
emit_signal("push_successful")
else:
emit_signal("push_failed")
if _push_queue.size() > 0:
push(_push_queue.pop_front())
52 changes: 28 additions & 24 deletions addons/godot-firebase/firebase/firebase.gd
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,40 @@ const ENVIRONMENT_VARIABLES : String = "firebase/environment_variables/"
onready var Auth : FirebaseAuth = $Auth
onready var Firestore : FirebaseFirestore = $Firestore
onready var Database : FirebaseDatabase = $Database
onready var Storage : FirebaseStorage = $Storage

# Configuration used by all files in this project
# These values can be found in your Firebase Project
# See the README on Github for how to access
var config : Dictionary = {
"apiKey": "",
"authDomain": "",
"databaseURL": "",
"projectId": "",
"storageBucket": "",
"messagingSenderId": "",
"appId": "",
"measurementId": "",
"clientId": "",
"clientSecret": "",
}
"apiKey": "",
"authDomain": "",
"databaseURL": "",
"projectId": "",
"storageBucket": "",
"messagingSenderId": "",
"appId": "",
"measurementId": "",
"clientId": "",
"clientSecret": "",
}

func load_config() -> void:
if ProjectSettings.has_setting(ENVIRONMENT_VARIABLES+"apiKey"):
for key in config.keys():
config[key] = ProjectSettings.get_setting(ENVIRONMENT_VARIABLES+key)
else:
printerr("No configuration settings found, add them in override.cfg file.")
if ProjectSettings.has_setting(ENVIRONMENT_VARIABLES+"apiKey"):
for key in config.keys():
config[key] = ProjectSettings.get_setting(ENVIRONMENT_VARIABLES+key)
else:
printerr("No configuration settings found, add them in override.cfg file.")

func _ready() -> void:
load_config()
Auth.set_config(config)
Firestore.set_config(config)
Database.set_config(config)
Auth.connect("login_succeeded", Database, "_on_FirebaseAuth_login_succeeded")
Auth.connect("signup_succeeded", Database, "_on_FirebaseAuth_login_succeeded")
Auth.connect("login_succeeded", Firestore, "_on_FirebaseAuth_login_succeeded")
Auth.connect("signup_succeeded", Firestore, "_on_FirebaseAuth_login_succeeded")
load_config()
Auth.set_config(config)
Firestore.set_config(config)
Database.set_config(config)
Storage.set_config(config)
Auth.connect("login_succeeded", Database, "_on_FirebaseAuth_login_succeeded")
Auth.connect("signup_succeeded", Database, "_on_FirebaseAuth_login_succeeded")
Auth.connect("login_succeeded", Firestore, "_on_FirebaseAuth_login_succeeded")
Auth.connect("signup_succeeded", Firestore, "_on_FirebaseAuth_login_succeeded")
Auth.connect("login_succeeded", Storage, "_on_FirebaseAuth_login_succeeded")
Auth.connect("signup_succeeded", Storage, "_on_FirebaseAuth_login_succeeded")
7 changes: 6 additions & 1 deletion addons/godot-firebase/firebase/firebase.tscn
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
[gd_scene load_steps=5 format=2]
[gd_scene load_steps=6 format=2]

[ext_resource path="res://addons/godot-firebase/database/database.gd" type="Script" id=1]
[ext_resource path="res://addons/godot-firebase/firestore/firestore.gd" type="Script" id=2]
[ext_resource path="res://addons/godot-firebase/firebase/firebase.gd" type="Script" id=3]
[ext_resource path="res://addons/godot-firebase/auth/auth.gd" type="Script" id=4]
[ext_resource path="res://addons/godot-firebase/storage/storage.gd" type="Script" id=5]

[node name="Firebase" type="Node"]
pause_mode = 2
script = ExtResource( 3 )

[node name="Firestore" type="Node" parent="."]
Expand All @@ -14,5 +16,8 @@ script = ExtResource( 2 )
[node name="Database" type="Node" parent="."]
script = ExtResource( 1 )

[node name="Storage" type="Node" parent="."]
script = ExtResource( 5 )

[node name="Auth" type="HTTPRequest" parent="."]
script = ExtResource( 4 )
56 changes: 28 additions & 28 deletions addons/godot-firebase/firestore/firestore.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,39 @@ var auth : Dictionary
var request_list_node : HTTPRequest

func set_config(config_json : Dictionary) -> void:
config = config_json
extended_url = extended_url.replace("[PROJECT_ID]", config.projectId)
request_list_node = HTTPRequest.new()
request_list_node.connect("request_completed", self, "on_list_request_completed")
add_child(request_list_node)
config = config_json
extended_url = extended_url.replace("[PROJECT_ID]", config.projectId)
request_list_node = HTTPRequest.new()
request_list_node.connect("request_completed", self, "on_list_request_completed")
add_child(request_list_node)

func collection(path : String) -> FirestoreCollection:
if !collections.has(path):
var coll : FirestoreCollection = FirestoreCollection.new()
coll.extended_url = extended_url
coll.base_url = base_url
coll.config = config
coll.auth = auth
coll.collection_name = path
collections[path] = coll
add_child(coll)
return coll
else:
return collections[path]
if !collections.has(path):
var coll : FirestoreCollection = FirestoreCollection.new()
coll.extended_url = extended_url
coll.base_url = base_url
coll.config = config
coll.auth = auth
coll.collection_name = path
collections[path] = coll
add_child(coll)
return coll
else:
return collections[path]

func list(path : String = "") -> void:
var url : String
if not path in [""," "]:
url = base_url + extended_url + path + "/"
else:
url = base_url + extended_url
request_list_node.request(url, ["Authorization: Bearer " + auth.idtoken], true, HTTPClient.METHOD_GET)
var url : String
if not path in [""," "]:
url = base_url + extended_url + path + "/"
else:
url = base_url + extended_url
request_list_node.request(url, ["Authorization: Bearer " + auth.idtoken], true, HTTPClient.METHOD_GET)

func on_list_request_completed(result : int, response_code : int, headers : PoolStringArray, body : PoolByteArray):
print(JSON.parse(body.get_string_from_utf8()).result)
print(JSON.parse(body.get_string_from_utf8()).result)

func _on_FirebaseAuth_login_succeeded(auth_result : Dictionary) -> void:
auth = auth_result
for collection_key in collections.keys():
collections[collection_key].auth = auth
pass
auth = auth_result
for collection_key in collections.keys():
collections[collection_key].auth = auth
pass
Loading

0 comments on commit cdbaf7d

Please sign in to comment.