heimdall stuff
This commit is contained in:
parent
2dddb0dc89
commit
ff8e103274
|
@ -0,0 +1,2 @@
|
|||
/.env.rb
|
||||
/hyde/
|
121
proto.rb
121
proto.rb
|
@ -1,6 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'weakref'
|
||||
|
||||
module Heimdall
|
||||
# Protocol error class
|
||||
class ProtoError < StandardError
|
||||
end
|
||||
|
||||
# Container for any uniquely identifiable object
|
||||
# @abstract
|
||||
class UUIDObject
|
||||
|
@ -18,43 +24,92 @@ module Heimdall
|
|||
|
||||
# Create a new UUIDObject with unique UUID
|
||||
# @return [self]
|
||||
def new
|
||||
object = super
|
||||
def new(*args, **params)
|
||||
object = super(*args, **params)
|
||||
@uuids[object.uuid] = object
|
||||
@last = object.uuid
|
||||
@foreign_ids[object.foreign_id] = object if object.foreign_id
|
||||
add_foreign(object.foreign_ids, object)
|
||||
object
|
||||
end
|
||||
|
||||
# Delete an object found by UUID
|
||||
# @param uuid [Integer]
|
||||
# @return [void]
|
||||
def delete(uuid)
|
||||
obj = @uuids[uuid]
|
||||
return false unless obj
|
||||
|
||||
@uuids.delete(obj.uuid)
|
||||
obj.foreign_ids.each { |x| @foreign_ids.delete(x) }
|
||||
true
|
||||
end
|
||||
|
||||
# Delete an object found by foreign id
|
||||
# @param foreign_id [String]
|
||||
# @return [void]
|
||||
def delete_foreign(foreign_id)
|
||||
obj = @foreign_ids[foreign_id]
|
||||
return false unless obj
|
||||
|
||||
@uuids.delete(obj.uuid)
|
||||
obj.foreign_ids.each { |x| @foreign_ids.delete(x) }
|
||||
true
|
||||
end
|
||||
|
||||
# Get object by UUID
|
||||
# @param uuid
|
||||
# @param uuid [Integer]
|
||||
# @return [self, nil]
|
||||
def get(uuid)
|
||||
@uuids[uuid] if @uuids[uuid].is_a? self
|
||||
end
|
||||
|
||||
# Get object by foreign id
|
||||
# @param foreign_id
|
||||
# @param foreign_id [String]
|
||||
# @return [self, nil]
|
||||
def get_foreign(foreign_id)
|
||||
@foreign_ids[foreign_id] if @foreign_ids[foreign_id].is_a? self
|
||||
end
|
||||
|
||||
# Add foreign ids to the list of known foreign ids
|
||||
# @param foreign [Array<String>]
|
||||
# @return [void]
|
||||
def add_foreign(foreign, obj)
|
||||
foreign.each do |f_id|
|
||||
@foreign_ids[check_foreign(f_id)] = obj
|
||||
end
|
||||
end
|
||||
|
||||
# Check a foreign id for valid syntax
|
||||
# @param foreign [String]
|
||||
# @return [String]
|
||||
def check_foreign(foreign)
|
||||
if foreign_ids.include?(foreign)
|
||||
raise ProtoError, 'foreign id already exists'
|
||||
end
|
||||
|
||||
unless foreign.match?(/^([\w_]+):.*$/)
|
||||
raise ProtoError, 'invalid foreign id syntax'
|
||||
end
|
||||
|
||||
foreign
|
||||
end
|
||||
|
||||
attr_accessor :uuids, :foreign_ids, :last
|
||||
end
|
||||
|
||||
def initialize
|
||||
@uuid = __gen_uuid
|
||||
@foreign_ids = []
|
||||
@foreign_ids.append(@id) if @id
|
||||
end
|
||||
|
||||
attr_reader :uuid, :foreign_id
|
||||
attr_reader :uuid, :foreign_ids
|
||||
|
||||
private
|
||||
|
||||
def __gen_uuid
|
||||
newuuid = (Time.now.to_f * 1000).to_i * 10000
|
||||
if (self.class.last / 1000) == (newuuid / 1000)
|
||||
if self.class.last && (self.class.last / 1000) == (newuuid / 1000)
|
||||
newuuid += (self.class.last % 1000) + 1
|
||||
end
|
||||
newuuid
|
||||
|
@ -103,13 +158,14 @@ module Heimdall
|
|||
# Message struct
|
||||
class Message < UUIDObject
|
||||
def initialize(datahash, **params)
|
||||
super(**params)
|
||||
|
||||
@id = datahash["id"]
|
||||
@from = UUIDObject.get(datahash["from"])
|
||||
@to = UUIDObject.get(datahash["to"])
|
||||
@content = datahash["content"]
|
||||
# @reply_to = datahash["reply_to"] # TODO: make this make sense
|
||||
@attachments = datahash["attachments"]
|
||||
|
||||
super(**params)
|
||||
end
|
||||
|
||||
attr_reader :from, :to, :content, :reply_to, :attachments
|
||||
|
@ -117,8 +173,51 @@ module Heimdall
|
|||
|
||||
# User struct
|
||||
class User < UUIDObject
|
||||
def initialize(datahash, **params)
|
||||
super(**params)
|
||||
DEFAULT_AVATAR = ""
|
||||
|
||||
def initialize(datahash, **params)
|
||||
@id = datahash["id"]
|
||||
@username = datahash["username"]
|
||||
@nickname = datahash["nickname"]
|
||||
@avatar = datahash["avatar"] || self.class::DEFAULT_AVATAR
|
||||
|
||||
super(**params)
|
||||
end
|
||||
|
||||
# Convert user data to a JSON struct
|
||||
# @return [String] JSON struct
|
||||
def to_struct
|
||||
JSON.dump({
|
||||
"id" => @id,
|
||||
"username" => @username,
|
||||
"nickname" => @nickname,
|
||||
"avatar" => @avatar
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
# Channel struct
|
||||
class Channel < UUIDObject
|
||||
DEFAULT_AVATAR = ""
|
||||
|
||||
def initialize(datahash, **params)
|
||||
@id = datahash["id"]
|
||||
@name = datahash["name"] or @id
|
||||
@avatar = datahash["avatar"] || self.class::DEFAULT_AVATAR
|
||||
|
||||
super(**params)
|
||||
end
|
||||
|
||||
# Convert channel data to a JSON struct
|
||||
# @return [String] JSON struct
|
||||
def to_struct
|
||||
JSON.dump({
|
||||
"id" => @id,
|
||||
"name" => @name,
|
||||
"avatar" => @avatar
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
VERSION = "1.0"
|
||||
end
|
||||
|
|
96
server.ru
96
server.ru
|
@ -8,6 +8,8 @@ require 'json'
|
|||
# Primary server class
|
||||
class HeimdallServer < Landline::App
|
||||
before do
|
||||
header "content-type", "application/json"
|
||||
|
||||
# Match data type against a list of datatypes
|
||||
# @param obj [Object]
|
||||
# @param type [Array, Class]
|
||||
|
@ -23,41 +25,103 @@ class HeimdallServer < Landline::App
|
|||
# @param args [Hash] hash of key - type pairs to check JSON data against
|
||||
def validate_json(**args)
|
||||
die(400, backtrace: ['JSON body expected']) unless json?
|
||||
data = begin
|
||||
@data = begin
|
||||
JSON.parse(request.body)
|
||||
rescue StandardError
|
||||
die(400, backtrace: ['JSON body is invalid'])
|
||||
end
|
||||
args.each do |k, v|
|
||||
unless data.include?(k) and match_type(data[k], v)
|
||||
die(400, backtrace: ["Key #{k} is missing"])
|
||||
unless match_type(@data[k], v)
|
||||
die(400, backtrace: ["Key #{k} of type #{v} is missing"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
filter do
|
||||
request.cookies["token"] == BOT_TOKEN
|
||||
defined? ::BOT_TOKEN ? request.cookies["token"] == ::BOT_TOKEN : true
|
||||
end
|
||||
|
||||
get "/version" do
|
||||
JSON.dump({
|
||||
"version" => Heimdall::VERSION
|
||||
})
|
||||
end
|
||||
|
||||
pipeline do |request, &output|
|
||||
output.call(request)
|
||||
rescue Heimdall::ProtoError => e
|
||||
throw :finish, [400,
|
||||
{ "content-type": "application/json" },
|
||||
JSON.dump({
|
||||
"error" => e.message,
|
||||
"code" => 400
|
||||
})]
|
||||
end
|
||||
|
||||
read_delete = proc do |cls|
|
||||
get "/foreign/*" do |id|
|
||||
user = cls.get_foreign(id)
|
||||
user&.to_struct or die(400, backtrace: ["#{cls} not found"])
|
||||
end
|
||||
|
||||
get "/uuid/*" do |id|
|
||||
user = cls.get(id.to_i)
|
||||
user&.to_struct or die(400, backtrace: ["#{cls} not found"])
|
||||
end
|
||||
|
||||
delete "/foreign/*" do |id|
|
||||
if cls.delete_foreign(id)
|
||||
JSON.dump({ "code" => 200 })
|
||||
else
|
||||
die(400, backtrace: ["#{cls} not found"])
|
||||
end
|
||||
end
|
||||
|
||||
delete "/uuid/*" do |id|
|
||||
if cls.delete(id.to_i)
|
||||
JSON.dump({ "code" => 200 })
|
||||
else
|
||||
die(400, backtrace: ["#{cls} not found"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path "/user" do
|
||||
post "/register" do
|
||||
validate_json("id" => Integer,
|
||||
validate_json("id" => String,
|
||||
"username" => String,
|
||||
"nickname" => [String, NilClass])
|
||||
|
||||
end
|
||||
"nickname" => [String, NilClass],
|
||||
"avatar" => [String, NilClass])
|
||||
new_user = Heimdall::User.new(@data)
|
||||
JSON.dump({ "uuid": new_user.uuid })
|
||||
end
|
||||
|
||||
handle do |status, backtrace: nil|
|
||||
page = JSON.dump({
|
||||
"error" => backtrace.join("\n"),
|
||||
"code" => status
|
||||
})
|
||||
[{
|
||||
"content-length": page.bytesize,
|
||||
instance_exec(Heimdall::User, &read_delete)
|
||||
end
|
||||
|
||||
path "/channel" do
|
||||
post "/register" do
|
||||
validate_json("id" => String,
|
||||
"name" => String,
|
||||
"avatar" => [String, NilClass])
|
||||
new_channel = Heimdall::Channel.new(@data)
|
||||
JSON.dump({ "uuid": new_channel.uuid })
|
||||
end
|
||||
|
||||
instance_exec(Heimdall::Channel, &read_delete)
|
||||
end
|
||||
|
||||
handle do |status, backtrace: nil, **_|
|
||||
backtrace ||= [Landline::Util::HTTP_STATUS[status]]
|
||||
[status,
|
||||
{
|
||||
"content-type": "application/json"
|
||||
}, page]
|
||||
},
|
||||
JSON.dump({
|
||||
"error" => (backtrace || []).join("\n"),
|
||||
"code" => status
|
||||
})]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue