diff --git a/client/index.ls b/client/index.ls index 1d16a5e..4309741 100644 --- a/client/index.ls +++ b/client/index.ls @@ -349,8 +349,8 @@ model = { } protocol = if location.protocol == 'https' then 'wss' else 'ws' -port = if location.port then \: + location.port else '' -socket-url = protocol + '://' + location.hostname + port + "/socket" +port = 9999 +socket-url = protocol + '://' + location.hostname + \: + port + "/kanban.JSON" console.log socket-url @@ -358,6 +358,7 @@ KanbanSocket = (socket-url) -> self = {} self.open-socket = -> + console.log "Opening socket to #{socket-url}" self.socket := new WebSocket socket-url self.socket.onerror = (event) -> @@ -374,7 +375,9 @@ KanbanSocket = (socket-url) -> projector.schedule-render! self.socket.onmessage = (event) -> - self.on-message event + payload = JSON.parse(event.data).payload + + self.on-message {data: payload} self.reopen = -> self.socket.close! @@ -383,29 +386,37 @@ KanbanSocket = (socket-url) -> self.open-socket! self.send = (opts) -> - self.socket.send opts + console.log JSON.stringify { + mtype: 0, + payload: opts + } + + self.socket.send JSON.stringify { + mtype: 0, + payload: opts + } self.get-project = (project-id) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "project", project: project-id } self.login = (login, password) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "login", login: login password: password } self.get-user = (uid) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "get-user" uid: uid } self.new-project = (name) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "new-project" name: name } @@ -420,10 +431,10 @@ KanbanSocket = (socket-url) -> for key, value of options payload[key] = value - self.socket.send JSON.stringify payload + self.send JSON.stringify payload self.delete-task = (project-id, task-id) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "delete-task" project: project-id task: task-id @@ -439,17 +450,17 @@ KanbanSocket = (socket-url) -> for key, value of options payload[key] = value - self.socket.send JSON.stringify payload + self.send JSON.stringify payload self.delete-column = (project-id, column-id) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "delete-column" project: project-id column: column-id } self.new-column = (project-id, name) -> - self.socket.send JSON.stringify { + self.send JSON.stringify { type: "new-column" project: project-id name: name @@ -465,7 +476,7 @@ KanbanSocket = (socket-url) -> for key, value of options payload[key] = value - self.socket.send JSON.stringify payload + self.send JSON.stringify payload self.edit-project = (project-id, options) -> payload = { @@ -476,15 +487,17 @@ KanbanSocket = (socket-url) -> for key, value of options payload[key] = value - self.socket.send JSON.stringify payload + self.send JSON.stringify payload self socket = KanbanSocket socket-url -socket.on-message = (event) -> - console.log event.data +socket.on-close = -> + model.current-view := "login" + socket.reopen! +socket.on-message = (event) -> message = JSON.parse event.data switch message.type diff --git a/shard.yml b/shard.yml index a4656c8..7f7fcb5 100644 --- a/shard.yml +++ b/shard.yml @@ -13,7 +13,7 @@ dependencies: authd: github: Lukc/authd fs: - git: https://git.karchnu.fr/JunkOS/fs.cr + git: https://git.karchnu.fr/WeirdOS/fs.cr # pg: # github: will/crystal-pg diff --git a/src/main.cr b/src/main.cr index 5ad4706..f7aa805 100644 --- a/src/main.cr +++ b/src/main.cr @@ -23,8 +23,37 @@ Kemal.config.extra_options do |parser| end end -sockets = [] of HTTP::WebSocket -users = {} of HTTP::WebSocket => AuthD::User +class ConnectionArray < Array(Int32) + def <<(x : IPC::Connection) + self << x.fd + end + + def [](key) : IPC::Connection + fd = fetch key + + connection = LibIPC::Connection.new# 0, 0, fd, 0, Pointer(UInt8).null + connection.fd = fd + IPC::Connection.new connection + end + + def each + super do |fd| + connection = LibIPC::Connection.new# 0, 0, fd, 0, Pointer(UInt8).null + connection.fd = fd + + yield IPC::Connection.new connection + end + end +end + +class ConnectionHash < Hash(Int32, AuthD::User) + def [](key : IPC::Connection) + self[key.fd] + end +end + +sockets = ConnectionArray.new +users = ConnectionHash.new get "/" do File.read "index.html" @@ -40,14 +69,28 @@ get "/main.js" do |env| File.read "main.js" end -ws "/socket" do |socket| - socket.on_close do +authd = AuthD::Client.new + +key = authd_key +authd.key = key if key.is_a? String + +IPC::Service.new "kanban" do |event| + case event + when IPC::Event::Connection + when IPC::Event::Disconnection + socket = event.connection + users.delete socket sockets.delete socket - end + when IPC::Event::Message + message_as_s = String.new event.message.payload + begin + message = JSON.parse(message_as_s).as_h + rescue + next # Dropping malformed requests. + end - socket.on_message do |message_as_s| - message = JSON.parse(message_as_s).as_h + connection = event.connection case message["type"] when "login" @@ -59,7 +102,7 @@ ws "/socket" do |socket| user = authd.get_user? login, password unless user - socket.send({ + connection.send(0, { type: "login-error", error: "Invalid credentials." }.to_json) @@ -67,19 +110,19 @@ ws "/socket" do |socket| next end - users[socket] = user - sockets << socket + users[connection.fd] = user + sockets << connection.fd - socket.send({ + connection.send(0, { type: "login" }.to_json) - socket.send({ + connection.send(0, { type: "list-projects", projects: Project.all storage_directory }.to_json) when "new-project" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::NewProject.from_json message_as_s @@ -88,28 +131,28 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "list-projects", projects: Project.all storage_directory }.to_json) - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "project" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::Tasks.from_json message_as_s project = Project.get_from_id request.project, storage_directory - socket.send({ + connection.send(0, { type: "project", project: project }.to_json) when "edit-project" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::EditProject.from_json message_as_s @@ -126,12 +169,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "new-column" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::NewColumn.from_json message_as_s @@ -141,12 +184,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "new-task" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::NewTask.from_json message_as_s @@ -158,12 +201,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "edit-task" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::EditTask.from_json message_as_s @@ -199,12 +242,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "delete-task" - user = users[socket] + user = users[connection] request = Requests::DeleteTask.from_json message_as_s @@ -215,12 +258,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "edit-column" - user = users[socket] # FIXME: make it an authentication error + user = users[connection] # FIXME: make it an authentication error request = Requests::EditColumn.from_json message_as_s @@ -236,12 +279,12 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) when "delete-column" - user = users[socket] + user = users[connection] request = Requests::DeleteColumn.from_json message_as_s project = Project.get_from_id request.project, storage_directory @@ -252,7 +295,7 @@ ws "/socket" do |socket| project.write! storage_directory # FIXME: Only notify concerned users. - sockets.each &.send({ + sockets.each &.send(0, { type: "project", project: project }.to_json) @@ -261,18 +304,13 @@ ws "/socket" do |socket| user = authd.get_user? request.uid - socket.send({ + connection.send(0, { type: "user", user: user }.to_json) end + else + pp event end end -Kemal.run do - authd = AuthD::Client.new - - key = authd_key - authd.key = key if key.is_a? String -end -