Compare commits

...

2 Commits

Author SHA1 Message Date
Yessiest 2dddb0dc89 skeleton for the rewrite 2024-05-11 17:28:45 +04:00
Yessiest abe6521fd6 the hard reset 2024-04-29 15:37:32 +04:00
10 changed files with 5799 additions and 1015 deletions

2
.bundle/config Normal file
View File

@ -0,0 +1,2 @@
---
BUNDLE_PATH: ".gems"

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "hyde"]
path = hyde
url = git@adastra7.net:Yessiest/hyde

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ domains: []
reporters:
- rubocop
- require_not_found
- typecheck:typed
formatter:
rubocop:
cops: safe

View File

@ -2,8 +2,6 @@
source "https://rubygems.org"
# gem "rails"
gem 'webrick'
gem 'mime-types'
gem 'webrick-websocket'
gem 'websocket'
gem 'landline'
gem 'puma'

185
client.rb
View File

@ -1,185 +0,0 @@
#!/usr/bin/ruby
require 'readline'
require 'net/http'
require 'json'
require 'websocket-client-simple'
require 'uri'
puts "Connecting to server #{ARGV[0]} on port #{ARGV[1]}"
def get(path)
where = URI("http://#{ARGV[0]}:#{ARGV[1]}/#{path}")
JSON.parse(Net::HTTP.get(where))
end
def post(path,data)
where = URI("http://#{ARGV[0]}:#{ARGV[1]}/#{path}")
Net::HTTP.post(where,data.to_json)
end
version = get("version")["version"]
puts "Server reported version: #{version}"
print "Nickname> "
nickname = $stdin.gets.strip
puts "Trying to log in..."
res = get("/user/exists?protocol_id=#{"heimdall-"+nickname}")
puts "Account exists! exiting" if res["exists"]
return if res["exists"]
puts "Creating account..."
test = post("/user/new",{username: nickname, protocol_id: "heimdall-"+nickname})
unless test.kind_of? Net::HTTPOK then
puts "Something went wrong! exiting"
exit
end
puts "Your id is: heimdall-#{nickname}"
puts "Establishing websocket connection..."
ws = WebSocket::Client::Simple.connect "ws://#{ARGV[0]}:#{ARGV[2]}"
ws.on :message do |msg|
data = JSON.parse(msg.data)
if data.has_key? "websocket" then
WEBSOCKET_UID = uid = data["websocket"]
response = post("/user/listen",{
websocket: uid,
protocol_id: "heimdall-"+nickname
})
unless response.kind_of? Net::HTTPOK then
puts "Something went wrong when initiating listening to user! Check server logs for info."
end
elsif data.has_key? "error" then
puts "ERROR: #{data["error"]}"
elsif data.has_key? "room" then
puts "[#{data["room"]["name"]}] #{data["user"]["username"]}: #{data["content"]}"
else
puts "#{data["user"]["username"]}: #{data["content"]}"
end
end
ws.on :open do |msg|
puts "Websocket connection established"
end
at_exit do
ws.close
end
target = nil
target_type = nil
at_exit do
post("/user/delete",{
"protocol_id"=> "heimdall-"+nickname
})
end
while buf = Readline.readline("", true)
if buf == "/help" then
puts "Commands:"
puts "/help - this message"
puts "/send <protcol_id> - direct messages to somebody"
puts "/exit - quit program"
puts "/find <username> - find a username by pattern"
puts "/find-protoid <protoid> - find by a protocol id"
puts "/username <username> - set your username (does not change your protocol id"
puts "/create-room <roomname> - create a room"
puts "/join <room id> - join a room"
puts "/leave <room> - leave a room"
puts "/send-room <room> - send messages to a room"
next
end
if buf == "/exit" then
post("/user/delete",{
"protocol_id"=> "heimdall-"+nickname
})
exit
end
if buf.match(/^\/send .*$/) then
target = buf.match(/^\/send ([^\s]*)$/)[1]
target_type = "user"
next
end
if buf.match(/^\/send-room .*$/) then
target = buf.match(/^\/send-room ([^\s]*)$/)[1]
target_type = "room"
next
end
if buf.match(/^\/join .*$/) and defined? WEBSOCKET_UID then
target = buf.match(/^\/join ([^\s]*)$/)[1]
if get("/room/exists?protocol_id=#{target}")["exists"] then
target_type = "room"
post("/room/listen", {
websocket: WEBSOCKET_UID,
protocol_id: target
})
else
target = nil
end
next
end
if buf.match(/^\/leave .*$/) and defined? WEBSOCKET_UID then
target = buf.match(/^\/leave ([^\s]*)$/)[1]
if get("/room/exists?protocol_id=#{target}")["exists"] then
post("/room/unlisten",{
websocket: WEBSOCKET_UID,
protocol_id: target
})
if target_type == "room" then
target = nil
end
end
end
if buf.match(/^\/find .*$/) then
uname = (buf.match /^\/find (.*)$/)[1]
users = get("/user/find/by-name?username=#{uname}")["results"]
puts "Found #{users.length} results: "
users.each { |x| puts x[0] }
next
end
if buf.match(/^\/find-protoid .*$/) then
pid = (buf.match /^\/find-protoid (.*)$/)[1]
users = get("/user/find/by-protoid?protocol_id=#{pid}")["results"]
puts "Found #{users.length} results: "
users.each { |x| puts x[0] }
next
end
if buf.match(/^\/username .*$/) then
uname = (buf.match /^\/username (.*)$/)[1]
post("/user/modify",{
data: {
username: uname
},
protocol_id: "heimdall-"+nickname
})
next
end
if buf.match(/^\/create-room \S+$/) then
name = (buf.match /^\/create-room (\S+)$/)[1]
post("/room/new",{
protocol_id: "heimdall-room-"+name,
name: name
})
puts("Room id: heimdall-room-#{name}")
end
if target and target_type then
if target_type == "user" then
post("/user/send", {
"to" => target,
"content" => buf,
"from" => "heimdall-"+nickname
})
elsif target_type == "room" then
post("/room/send", {
"to" => target,
"content" => buf,
"from" => "heimdall-"+nickname
})
end
end
end

1
hyde

@ -1 +0,0 @@
Subproject commit fd76422b760e6c045581bcb11842ee42221d06e0

311
proto.rb
View File

@ -1,221 +1,124 @@
UIDS = {}
# frozen_string_literal: true
module Heimdall
VERSION = "0.99 beta"
attr_reader :VERSION
class ProtocolError < StandardError
end
class UID
def initialize
@UID_prefix = "abstract" if not @UID_prefix
id = (1..32).map { |x| (rand()*10).floor }.join
while UIDS.has_key? id do
id = (1..32).map { |x| (rand()*10).floor }.join
# Container for any uniquely identifiable object
# @abstract
class UUIDObject
UUIDSYM = (('0'..'9').to_a + ('a'..'f').to_a).freeze
class << self
# Add uuids to subclass
def inherited(subclass)
@uuids ||= {}
@foreign_ids ||= {}
@last ||= 0
super(subclass)
subclass.uuids = @uuids
subclass.foreign_ids = @foreign_ids
end
UIDS[@UID_prefix+id] = self
@UID = id
end
attr_reader :UID
end
class UserCache
# Create a new UUIDObject with unique UUID
# @return [self]
def new
object = super
@uuids[object.uuid] = object
@last = object.uuid
@foreign_ids[object.foreign_id] = object if object.foreign_id
object
end
# Get object by UUID
# @param uuid
# @return [self, nil]
def get(uuid)
@uuids[uuid] if @uuids[uuid].is_a? self
end
# Get object by foreign id
# @param foreign_id
# @return [self, nil]
def get_foreign(foreign_id)
@foreign_ids[foreign_id] if @foreign_ids[foreign_id].is_a? self
end
attr_accessor :uuids, :foreign_ids, :last
end
def initialize
@users = {}
@uuid = __gen_uuid
@foreign_ids = []
end
def sync(data)
data.each { |userdata|
if not @users[userdata["protocol_id"]] then
new_user = User.new userdata
@users[new_user.protoid] = new_user
else
@users[userdata["protocol_id"]].modify(userdata)
end
}
end
def add(user)
@users[user.protoid] = user
end
def get(protoid)
raise ProtocolError, "user not found" if not @users[protoid]
return @users[protoid]
end
def search(name,n,&block)
@users.select(&block).take(n)
end
def search_by_name(name, n = 10)
search(name,n) { |k,v| v.username.match? name }
end
def search_by_protoid(name,n = 10)
search(name,n) { |k,v| k.match? name }
end
def filter(&block)
@users.filter &block
end
def delete(protoid)
@users.delete protoid
end
def bulk_delete(protoid_list)
protoid_list.each { |x| @users.delete x }
end
end
class RoomCache < UserCache
def get(protoid)
raise ProtocolError, "room not found" if not @users[protoid]
return @users[protoid]
end
def sync(data)
data.each { |userdata|
if not @users[userdata["protocol_id"]] then
new_user = Room.new userdata
@users[new_user.protoid] = new_user
else
@users[userdata["protocol_id"]].modify(userdata)
end
}
attr_reader :uuid, :foreign_id
private
def __gen_uuid
newuuid = (Time.now.to_f * 1000).to_i * 10000
if (self.class.last / 1000) == (newuuid / 1000)
newuuid += (self.class.last % 1000) + 1
end
newuuid
end
end
class RoomFilter
def initialize(cache, room_protoid)
@cache = cache
@filter = room_protoid
end
def get(protoid)
raise ProtocolError, "user not found" if not _filter[protoid]
return _filter[protoid]
end
private
def _filter
@cache.filter { |k,v|
v.protoid == @filter
}
end
end
class User < UID
def initialize(data)
@username = data["username"]
@protoid = data["protocol_id"]
@UID_prefix = "user"
@channel = DirectChannel.new
super()
end
def to_card()
return {
"username" => @username,
"protoid" => @protoid
}
end
def modify(data)
@username = data["username"]
end
attr_reader :username
attr_reader :protoid
attr_reader :channel
end
class Room < UID
def initialize(data)
@name = data["name"]
@protoid = data["protocol_id"]
@UID_prefix = "room"
@channel = RoomChannel.new
@users = {}
super()
end
def to_card()
return {
"name" => @name,
"protoid" => @protoid
}
end
def modify(data)
@name = data["name"]
end
attr_reader :users
attr_reader :username
attr_reader :protoid
attr_reader :channel
end
class Channel < UID
def initialize
@UID_prefix = "channel"
@messages = MsgStack.new
@read = 0
super()
end
def send(msg)
@messages.push(msg)
@read = @read+1
end
def send_silent(msg)
@messages.push(msg)
end
def get(n = 1)
raise Heimdall::ProtocolError, "Invalid number of messages" if n < 0
return @messages.pull(n)
end
def read()
messages = @messages.pull(@read)
@read = 0
return messages
end
end
class DirectChannel < Channel
def initialize
@UID_prefix = "dchannel"
super()
end
end
class RoomChannel < Channel
def initialize
@UID_prefix = "schannel"
super()
end
undef read
def get(n = 1)
@read = 0
super(n)
end
end
class Message < UID
def initialize(data)
@content = data["content"]
@from = data["from"]
@to = data["to"]
@UID_prefix = "message"
super()
end
def to_struct
return {
"content" => @content,
"from" => @from,
"to" => @to
}
end
attr_reader :content
attr_reader :from
attr_reader :to
end
class MsgStack < UID
def initialize
@UID_prefix = "msgstack"
# PubSub abstract container
# @abstract
class PubSub
def initialize(buffer_size: 1024)
@buffer_size = buffer_size
@listeners = []
@messages = []
super()
end
# Push message to all listeners
# @param msg [UUIDObject]
# @return [void]
def push(msg)
@listeners.each { |x| x.call(msg) }
@messages.append(msg)
@messages.shift if @messages.length > @buffer_size
end
def pull(n)
@messages.last n
# Add a listener to the PubSub
# @param listener [#call]
# @return [void]
def listen(listener)
@listeners.append(listener)
end
# Pull all messages since UUID
# @param uuid [String]
# @return [Array<UUIDObject>]
def pull(uuid)
output = []
@messages.reverse_each do |x|
break if x.uuid < uuid
output.unshift(x)
end
output
end
end
# Message struct
class Message < UUIDObject
def initialize(datahash, **params)
super(**params)
@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"]
end
attr_reader :from, :to, :content, :reply_to, :attachments
end
# User struct
class User < UUIDObject
def initialize(datahash, **params)
super(**params)
@id = datahash["id"]
end

604
server.rb
View File

@ -1,604 +0,0 @@
require_relative "proto"
require_relative "hyde/hyde"
require 'webrick/websocket'
require "json"
Users = Heimdall::UserCache.new
Rooms = Heimdall::RoomCache.new
SocketsMap = {}
NotifyList = {}
def _require_keys(dict,key_dict)
raise KeyError, "not a dict" unless dict.kind_of? Hash
key_dict.each_pair { |k,v|
unless (dict.has_key? k.to_s) and (dict[k.to_s].kind_of? v) then
raise KeyError, "key #{k} of type #{v} required"
end
}
end
def _send_json(res,data,code: 200)
res.body = JSON::fast_generate(data)
res['Content-Type'] = "application/json"
res.status = code
end
def _throw_error(res,error)
_send_json(res,{
error: "#{error}"
},code: 400)
end
def _parse_json(body,key_dict)
data = JSON::Parser.new(body).parse
_require_keys(data,key_dict)
return data
end
server = Hyde::Server.new Port: 8000 do
path "user" do
path "find" do
index ["by-name"]
get "by-name" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
username: String
})
_send_json(res, {
"results": Users.search_by_name(req.query['username']).map { |x| x[1].to_card }
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
end
end
get "by-protoid" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
protocol_id: String
})
_send_json(res, {
"results": Users.search_by_protoid(req.query['protocol_id']).map { |x| x[1].to_card; x }
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
end
end
end
post "sync" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
data: Array
})
Users.sync(data["data"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "bulk-delete" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
users: Array
})
Users.bulk_delete(data["users"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
get "exists" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
protocol_id: String
})
_send_json(res,{
exists: (Users.get(req.query["protocol_id"]) != nil)
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue Heimdall::ProtocolError => protoerr
_send_json(res, {
exists: false
})
end
end
post "new" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body,{
username: String,
protocol_id: String
})
new_user = Heimdall::User.new(data)
Users.add(new_user)
_send_json(res,{
status: true
})
NotifyList[new_user.UID] = []
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
post "modify" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
data: Hash,
protocol_id: String
})
user = Users.get(data["protocol_id"])
user.modify(data["data"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue ProtocolError => protoerr
_throw_error(res,protoerr)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "send" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
content: String,
from: String,
to: String
})
new_message = Heimdall::Message.new(data)
user = Users.get(new_message.to)
if NotifyList[user.UID].length != 0 then
NotifyList[user.UID].each { |sockid|
sock = SocketsMap[sockid]
msg = new_message.to_struct
msg["user"] = Users.get(msg["from"]).to_card
sock.puts(JSON::fast_generate(msg))
}
user.channel.send_silent(new_message)
else
user.channel.send(new_message)
end
_send_json(res,{
status: true
})
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
get "get" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query,{
n: Integer,
protocol_id: String
})
number = req.query[:n]
id = req.query["protocol_id"]
user = Users.get(id)
messages = user.channel.get(number)
_send_json(res, {
messages: messages.map { |x|
x = x.to_struct
x["user"] = Users.get(x["from"]).to_card
x
}
})
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
get "read" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query,{
protocol_id: String
})
id = req.query["protocol_id"]
user = Users.get(id)
messages = user.channel.read
_send_json(res, {
messages: messages.map { |x|
x = x.to_struct
x["user"] = Users.get(x["from"]).to_card
x
}
})
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
post "listen" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body, {
websocket: String,
protocol_id: String
})
uid = Users.get(data["protocol_id"]).UID
raise KeyError, "websocket does not exist" unless SocketsMap.has_key? data["websocket"]
NotifyList[uid].append data["websocket"]
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "unlisten" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body, {
websocket: String,
protocol_id: String
})
uid = Users.get(data["protocol_id"]).UID
raise KeyError, "websocket does not exist" unless SocketsMap.has_key? data["websocket"]
NotfiyList[uid].delete data["websocket"]
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "delete" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body,{
protocol_id: String
})
id = data["protocol_id"]
_send_json(res, {
status: true
})
user = Users.get(id)
NotifyList.delete(user.UID)
Users.delete(id)
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
end
path "room" do
path "find" do
index ["by-name"]
get "by-name" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
username: String
})
_send_json(res, {
"results": Rooms.search_by_name(req.query['username']).map { |x| x[1].to_card }
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
end
end
get "by-protoid" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
protocol_id: String
})
_send_json(res, {
"results": Rooms.search_by_protoid(req.query['protocol_id']).map { |x| x[1].to_card; x }
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
end
end
end
post "new" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
name: String,
protocol_id: String
})
new_room = Heimdall::Room.new(data)
Rooms.add(new_room)
_send_json(res, {
status: true
})
NotifyList[new_room.UID] = []
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "send" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
content: String,
from: String,
to: String
})
new_message = Heimdall::Message.new(data)
room = Rooms.get(new_message.to)
if NotifyList[room.UID].length != 0 then
NotifyList[room.UID].each { |sockid|
sock = SocketsMap[sockid]
msg = new_message.to_struct
msg["user"] = Users.get(msg["from"]).to_card
msg["room"] = room.to_card
sock.puts(JSON::fast_generate(msg))
}
room.channel.send_silent(new_message)
else
room.channel.send(new_message)
end
_send_json(res,{
status: true
})
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
get "get" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query,{
n: Integer,
protocol_id: String
})
number = req.query[:n]
id = req.query["protocol_id"]
room = Rooms.get(id)
messages = room.channel.get(number)
_send_json(res, {
messages: messages.map { |x|
x = x.to_struct
x["user"] = Users.get(x["from"]).to_card
x["room"] = room.to_card
x
}
})
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
end
end
post "listen" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body, {
websocket: String,
protocol_id: String
})
uid = Rooms.get(data["protocol_id"]).UID
raise KeyError, "websocket does not exist" unless SocketsMap.has_key? data["websocket"]
NotifyList[uid].append data["websocket"]
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "unlisten" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body, {
websocket: String,
protocol_id: String
})
uid = Rooms.get(data["protocol_id"]).UID
raise KeyError, "websocket does not exist" unless SocketsMap.has_key? data["websocket"]
NotfiyList[uid].delete data["websocket"]
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "modify" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
data: Hash,
protocol_id: String
})
room = Rooms.get(data["protocol_id"])
room.modify(data["data"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue ProtocolError => protoerr
_throw_error(res,protoerr)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "delete" do |ctx|
req,res = ctx.request, ctx.response
begin
data = _parse_json(req.body,{
protocol_id: String
})
id = data["protocol_id"]
_send_json(res, {
status: true
})
room = Rooms.get(id)
NotifyList.delete(room.UID)
Rooms.delete(id)
rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "sync" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
data: Array
})
Rooms.sync(data["data"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
post "bulk-delete" do |ctx|
req,res = ctx.request,ctx.response
begin
data = _parse_json(req.body, {
users: Array
})
Rooms.bulk_delete(data["users"])
_send_json(res, {
status: true
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end
end
get "exists" do |ctx|
req,res = ctx.request,ctx.response
begin
_require_keys(req.query, {
protocol_id: String
})
_send_json(res,{
exists: (Rooms.get(req.query["protocol_id"]) != nil)
})
rescue KeyError => keyerror
_throw_error(res,keyerror)
rescue Heimdall::ProtocolError => protoerr
_send_json(res, {
exists: false
})
end
end
end
get "version" do |ctx|
ctx.response.body = "{\"version\":\"#{Heimdall::VERSION}\"}"
ctx.response['Content-Type'] = "application/json"
end
end
at_exit do
server.shutdown
end
class WebsocketUID < Heimdall::UID
def initialize
@UID_prefix = "websocket"
super
end
end
class EventServlet < WEBrick::Websocket::Servlet
def socket_open(sock)
@UID = WebsocketUID.new
@connected_listeners = []
SocketsMap[@UID.UID] = sock
sock.puts(JSON::fast_generate({
websocket: @UID.UID.to_s
}))
end
def socket_close(sock)
SocketsMap.delete @UID.UID
NotifyList.each do |k,v|
if v.include? @UID.UID
v.delete @UID.UID
end
end
end
def socket_text(sock,text)
# do nothing
end
end
Thread.new do
websocket_server = WEBrick::Websocket::HTTPServer.new Port:8001
websocket_server.mount "/", EventServlet
websocket_server.start
at_exit do
websocket_server.shutdown
end
end
server.start

64
server.ru Normal file
View File

@ -0,0 +1,64 @@
# frozen_string_literal: true
require_relative '.env'
require_relative 'proto'
require 'landline'
require 'json'
# Primary server class
class HeimdallServer < Landline::App
before do
# Match data type against a list of datatypes
# @param obj [Object]
# @param type [Array, Class]
def match_type(obj, type)
if type.is_a? Array
type.any? { |t| obj.is_a? t }
else
obj.is_a? type
end
end
# Validate json body for a post request
# @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
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"])
end
end
end
end
filter do
request.cookies["token"] == BOT_TOKEN
end
path "/user" do
post "/register" do
validate_json("id" => Integer,
"username" => String,
"nickname" => [String, NilClass])
end
end
handle do |status, backtrace: nil|
page = JSON.dump({
"error" => backtrace.join("\n"),
"code" => status
})
[{
"content-length": page.bytesize,
"content-type": "application/json"
}, page]
end
end
run HeimdallServer.new