nearing beta release

This commit is contained in:
Yessiest 2023-05-13 02:46:42 +04:00
parent 8d698d7fef
commit c151429e85
3 changed files with 504 additions and 23 deletions

View File

@ -35,7 +35,7 @@ ws = WebSocket::Client::Simple.connect "ws://#{ARGV[0]}:#{ARGV[2]}"
ws.on :message do |msg| ws.on :message do |msg|
data = JSON.parse(msg.data) data = JSON.parse(msg.data)
if data.has_key? "websocket" then if data.has_key? "websocket" then
uid = data["websocket"] WEBSOCKET_UID = uid = data["websocket"]
response = post("/user/listen",{ response = post("/user/listen",{
websocket: uid, websocket: uid,
protocol_id: "heimdall-"+nickname protocol_id: "heimdall-"+nickname
@ -45,6 +45,8 @@ ws.on :message do |msg|
end end
elsif data.has_key? "error" then elsif data.has_key? "error" then
puts "ERROR: #{data["error"]}" puts "ERROR: #{data["error"]}"
elsif data.has_key? "room" then
puts "[#{data["room"]["name"]}] #{data["user"]["username"]}: #{data["content"]}"
else else
puts "#{data["user"]["username"]}: #{data["content"]}" puts "#{data["user"]["username"]}: #{data["content"]}"
end end
@ -59,6 +61,7 @@ at_exit do
end end
target = nil target = nil
target_type = nil
at_exit do at_exit do
post("/user/delete",{ post("/user/delete",{
@ -66,7 +69,7 @@ at_exit do
}) })
end end
while buf = Readline.readline("> ", true) while buf = Readline.readline("", true)
if buf == "/help" then if buf == "/help" then
puts "Commands:" puts "Commands:"
puts "/help - this message" puts "/help - this message"
@ -74,6 +77,11 @@ while buf = Readline.readline("> ", true)
puts "/exit - quit program" puts "/exit - quit program"
puts "/find <username> - find a username by pattern" puts "/find <username> - find a username by pattern"
puts "/find-protoid <protoid> - find by a protocol id" 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 next
end end
@ -86,12 +94,46 @@ while buf = Readline.readline("> ", true)
if buf.match(/^\/send .*$/) then if buf.match(/^\/send .*$/) then
target = buf.match(/^\/send ([^\s]*)$/)[1] target = buf.match(/^\/send ([^\s]*)$/)[1]
target_type = "user"
next next
end 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 if buf.match(/^\/find .*$/) then
uname = (buf.match /^\/find (.*)$/)[1] uname = (buf.match /^\/find (.*)$/)[1]
users = get("/user/find/by-username?username=#{uname}")["results"] users = get("/user/find/by-name?username=#{uname}")["results"]
puts "Found #{users.length} results: " puts "Found #{users.length} results: "
users.each { |x| puts x[0] } users.each { |x| puts x[0] }
next next
@ -105,11 +147,39 @@ while buf = Readline.readline("> ", true)
next next
end end
if target then 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", { post("/user/send", {
"to" => target, "to" => target,
"content" => buf, "content" => buf,
"from" => "heimdall-"+nickname "from" => "heimdall-"+nickname
}) })
elsif target_type == "room" then
post("/room/send", {
"to" => target,
"content" => buf,
"from" => "heimdall-"+nickname
})
end
end end
end end

View File

@ -1,7 +1,7 @@
UIDS = {} UIDS = {}
module Heimdall module Heimdall
VERSION = "0.4 alpha" VERSION = "0.99 beta"
attr_reader :VERSION attr_reader :VERSION
class ProtocolError < StandardError class ProtocolError < StandardError
@ -24,6 +24,16 @@ module Heimdall
def initialize def initialize
@users = {} @users = {}
end 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) def add(user)
@users[user.protoid] = user @users[user.protoid] = user
end end
@ -34,15 +44,55 @@ module Heimdall
def search(name,n,&block) def search(name,n,&block)
@users.select(&block).take(n) @users.select(&block).take(n)
end end
def search_by_username(name, n = 10) def search_by_name(name, n = 10)
search(name,n) { |k,v| v.username.match? name } search(name,n) { |k,v| v.username.match? name }
end end
def search_by_protoid(name,n = 10) def search_by_protoid(name,n = 10)
search(name,n) { |k,v| k.match? name } search(name,n) { |k,v| k.match? name }
end end
def filter(&block)
@users.filter &block
end
def delete(protoid) def delete(protoid)
@users.delete protoid @users.delete protoid
end 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
}
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 end
class User < UID class User < UID
@ -50,7 +100,7 @@ module Heimdall
@username = data["username"] @username = data["username"]
@protoid = data["protocol_id"] @protoid = data["protocol_id"]
@UID_prefix = "user" @UID_prefix = "user"
@direct = DirectChannel.new @channel = DirectChannel.new
super() super()
end end
def to_card() def to_card()
@ -59,9 +109,36 @@ module Heimdall
"protoid" => @protoid "protoid" => @protoid
} }
end end
def modify(data)
@username = data["username"]
end
attr_reader :username attr_reader :username
attr_reader :protoid attr_reader :protoid
attr_reader :direct 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 end
class Channel < UID class Channel < UID
@ -101,6 +178,11 @@ module Heimdall
@UID_prefix = "schannel" @UID_prefix = "schannel"
super() super()
end end
undef read
def get(n = 1)
@read = 0
super(n)
end
end end
class Message < UID class Message < UID

345
server.rb
View File

@ -4,6 +4,8 @@ require 'webrick/websocket'
require "json" require "json"
Users = Heimdall::UserCache.new Users = Heimdall::UserCache.new
Rooms = Heimdall::RoomCache.new
SocketsMap = {} SocketsMap = {}
NotifyList = {} NotifyList = {}
@ -38,16 +40,16 @@ end
server = Hyde::Server.new Port: 8000 do server = Hyde::Server.new Port: 8000 do
path "user" do path "user" do
path "find" do path "find" do
index ["by-username"] index ["by-name"]
get "by-username" do |ctx| get "by-name" do |ctx|
req,res = ctx.request,ctx.response req,res = ctx.request,ctx.response
begin begin
_require_keys(req.query, { _require_keys(req.query, {
username: String username: String
}) })
_send_json(res, { _send_json(res, {
"results": Users.search_by_username(req.query['username']) "results": Users.search_by_name(req.query['username']).map { |x| x[1].to_card }
}) })
rescue KeyError => keyerror rescue KeyError => keyerror
_throw_error(res,keyerror) _throw_error(res,keyerror)
@ -61,7 +63,7 @@ server = Hyde::Server.new Port: 8000 do
protocol_id: String protocol_id: String
}) })
_send_json(res, { _send_json(res, {
"results": Users.search_by_protoid(req.query['protocol_id']) "results": Users.search_by_protoid(req.query['protocol_id']).map { |x| x[1].to_card; x }
}) })
rescue KeyError => keyerror rescue KeyError => keyerror
_throw_error(res,keyerror) _throw_error(res,keyerror)
@ -69,6 +71,40 @@ server = Hyde::Server.new Port: 8000 do
end 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| get "exists" do |ctx|
req,res = ctx.request,ctx.response req,res = ctx.request,ctx.response
begin begin
@ -104,6 +140,29 @@ server = Hyde::Server.new Port: 8000 do
_throw_error(res,jsonerror) _throw_error(res,jsonerror)
rescue KeyError => keyerror rescue KeyError => keyerror
_throw_error(res,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
end end
@ -124,9 +183,9 @@ server = Hyde::Server.new Port: 8000 do
msg["user"] = Users.get(msg["from"]).to_card msg["user"] = Users.get(msg["from"]).to_card
sock.puts(JSON::fast_generate(msg)) sock.puts(JSON::fast_generate(msg))
} }
user.direct.send_silent(new_message) user.channel.send_silent(new_message)
else else
user.direct.send(new_message) user.channel.send(new_message)
end end
_send_json(res,{ _send_json(res,{
status: true status: true
@ -150,7 +209,7 @@ server = Hyde::Server.new Port: 8000 do
number = req.query[:n] number = req.query[:n]
id = req.query["protocol_id"] id = req.query["protocol_id"]
user = Users.get(id) user = Users.get(id)
messages = user.direct.get(number) messages = user.channel.get(number)
_send_json(res, { _send_json(res, {
messages: messages.map { |x| messages: messages.map { |x|
x = x.to_struct x = x.to_struct
@ -171,7 +230,7 @@ server = Hyde::Server.new Port: 8000 do
}) })
id = req.query["protocol_id"] id = req.query["protocol_id"]
user = Users.get(id) user = Users.get(id)
messages = user.direct.read messages = user.channel.read
_send_json(res, { _send_json(res, {
messages: messages.map { |x| messages: messages.map { |x|
x = x.to_struct x = x.to_struct
@ -199,6 +258,28 @@ server = Hyde::Server.new Port: 8000 do
}) })
rescue KeyError => keyerror rescue KeyError => keyerror
_throw_error(res,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
end end
@ -217,10 +298,258 @@ server = Hyde::Server.new Port: 8000 do
Users.delete(id) Users.delete(id)
rescue Heimdall::ProtocolError => protoerr rescue Heimdall::ProtocolError => protoerr
_throw_error(res,protoerr) _throw_error(res,protoerr)
rescue JSON::ParserError => jsonerror
_throw_error(res,jsonerror)
end end
end 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| get "version" do |ctx|
ctx.response.body = "{\"version\":\"#{Heimdall::VERSION}\"}" ctx.response.body = "{\"version\":\"#{Heimdall::VERSION}\"}"
ctx.response['Content-Type'] = "application/json" ctx.response['Content-Type'] = "application/json"