diff --git a/app/assets/javascripts/signaling-server.js b/app/assets/javascripts/signaling-server.js index b77bc6e..25db06a 100644 --- a/app/assets/javascripts/signaling-server.js +++ b/app/assets/javascripts/signaling-server.js @@ -17,6 +17,7 @@ let localstream; window.onload = () => { currentUser = document.getElementById("current-user").innerHTML; + console.log(currentUser) localVideo = document.getElementById("local-video"); remoteVideoContainer = document.getElementById("remote-video-container"); }; @@ -40,17 +41,49 @@ document.onreadystatechange = async () => { } }; +// find chatroom +// const handleJoinSession = async () => { +// App.session = await App.cable.subscriptions.create("VideoSessionChannel", { +// connected: () => { +// broadcastData({ +// type: JOIN_ROOM, +// from: currentUser +// }); +// }, +// received: data => { +// console.log("received", data); +// if (data.from === currentUser) return; +// switch (data.type) { +// case JOIN_ROOM: +// return joinRoom(data); +// case EXCHANGE: +// if (data.to !== currentUser) return; +// return exchange(data); +// case REMOVE_USER: +// return removeUser(data); +// default: +// return; +// } +// } +// }); +// }; +const chatroomId = document.getElementById('chatroom-hook').dataset["chatroomId"] const handleJoinSession = async () => { - App.session = await App.cable.subscriptions.create("VideoSessionChannel", { + App['chatroom' + chatroomId] = await App.cable.subscriptions.create({ + channel: "ChatRoomsChannel", + room: chatroomId + }, { connected: () => { + console.log(chatroomId) broadcastData({ type: JOIN_ROOM, - from: currentUser + from: currentUser, + room: chatroomId }); }, received: data => { - console.log("received", data); + console.log(data) if (data.from === currentUser) return; switch (data.type) { case JOIN_ROOM: @@ -88,7 +121,6 @@ const joinRoom = data => { }; const removeUser = data => { - console.log("removing user", data.from); let video = document.getElementById(`remoteVideoContainer+${data.from}`); video && video.remove(); delete pcPeers[data.from]; @@ -96,18 +128,21 @@ const removeUser = data => { const broadcastData = data => { - fetch("sessions", { + if (data.type === EXCHANGE) { + console.log("yayyy") + } + fetch("chat_room_sessions", { method: "POST", body: JSON.stringify(data), - headers: { "content-type": "application/json" } + headers: { "content-type": "application/json", "X-CSRF-Token": document.querySelector('meta[name=csrf-token]').content } }); }; const createPC = (userId, isOffer) => { let pc = new RTCPeerConnection(ice); + let test = userId pcPeers[userId] = pc; pc.addStream(localstream); - if (isOffer) { pc .createOffer() @@ -117,7 +152,8 @@ const createPC = (userId, isOffer) => { type: EXCHANGE, from: currentUser, to: userId, - sdp: JSON.stringify(pc.localDescription) + sdp: JSON.stringify(pc.localDescription), + room: chatroomId }); }) .catch(logError); @@ -129,7 +165,8 @@ const createPC = (userId, isOffer) => { type: EXCHANGE, from: currentUser, to: userId, - candidate: JSON.stringify(event.candidate) + candidate: JSON.stringify(event.candidate), + room: chatroomId }); } }; @@ -186,7 +223,8 @@ const exchange = data => { type: EXCHANGE, from: currentUser, to: data.from, - sdp: JSON.stringify(pc.localDescription) + sdp: JSON.stringify(pc.localDescription), + room: chatroomId }); }); } diff --git a/app/assets/stylesheets/pages/_contacts.scss b/app/assets/stylesheets/pages/_contacts.scss index cb071eb..b1de415 100644 --- a/app/assets/stylesheets/pages/_contacts.scss +++ b/app/assets/stylesheets/pages/_contacts.scss @@ -50,6 +50,10 @@ a:hover { color: $icon; font-size: 25px; } + button { + height: 0; + width: 0; + } } } diff --git a/app/channels/chat_rooms_channel.rb b/app/channels/chat_rooms_channel.rb new file mode 100644 index 0000000..20b3201 --- /dev/null +++ b/app/channels/chat_rooms_channel.rb @@ -0,0 +1,9 @@ +class ChatRoomsChannel < ApplicationCable::Channel + def subscribed + stream_from "chat_room_#{params[:room]}" + end + + def unsubscribed + # Any cleanup needed when channel is unsubscribed + end +end diff --git a/app/channels/notifications_channel.rb b/app/channels/notifications_channel.rb new file mode 100644 index 0000000..ad0ec43 --- /dev/null +++ b/app/channels/notifications_channel.rb @@ -0,0 +1,9 @@ +class NotificationsChannel < ApplicationCable::Channel + def subscribed + stream_from "notifications" + end + + def unsubscribed + # Any cleanup needed when channel is unsubscribed + end +end diff --git a/app/controllers/chat_rooms_controller.rb b/app/controllers/chat_rooms_controller.rb new file mode 100644 index 0000000..37b681c --- /dev/null +++ b/app/controllers/chat_rooms_controller.rb @@ -0,0 +1,24 @@ +class ChatRoomsController < ApplicationController + + def show + @chat_room = ChatRoom.find(params[:id]) + end + + def create + # HTTP status code 200 with an empty body + head :no_content + puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>11123213213213123213" + puts params + puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>11123213213213123213" + + ActionCable.server.broadcast "chat_room_#{params[:room]}", session_params + end + + private + + def session_params + # SDP = Session description protocol (codec info from client) + # Candidate = ICE candidates (e.g. TURN and STUN server) + params.permit(:type, :from, :to, :sdp, :candidate, :room) + end +end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 8aa4a2a..efd5757 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -1,5 +1,6 @@ class PagesController < ApplicationController # skip_before_action :authenticate_user!, only: [:call] + skip_before_action :verify_authenticity_token def call end @@ -9,4 +10,63 @@ class PagesController < ApplicationController def home end + + def cable_testing + chatroom = 'chat_room_' + params[:chat_room_id] + puts params + ActionCable.server.broadcast(chatroom, { message: 'test' }) + head :ok + end + + def establish_call + head :ok + puts "params: #{params}" + chat_room = ChatRoom.create! + puts "Created chat room with id: #{chat_room.id}" + chat_room_participation = ChatRoomParticipation.create!(chat_room: chat_room, user: current_user) + puts "Created chat room participation with user: #{current_user.email} assigned to chat_room #{chat_room.id}" + puts "Subscribed user to chat room" + + contact = User.find(params[:contact_id]) + request = Request.create!(chat_room: chat_room, user: contact) + puts "Made a request to call #{contact.email}" + ActionCable.server.broadcast('notifications', { + message: { + user_id: contact.id, + chat_room_id: chat_room.id + } + }) + + end + + def accept_call + puts "-----------------------------------------" + puts params + puts "IT WORKED" + chat_room = ChatRoom.find(params[:chat_room_id]) + request = Request.where("user_id = ? AND chat_room_id = ?", current_user.id, chat_room.id) + + request[0].accepted = true + puts "create new chat room participation" + chat_room_participation = ChatRoomParticipation.create!(chat_room: chat_room, user: current_user) + puts "Created chat room participation with user: #{current_user.email} assigned to chat_room #{chat_room.id}" + + other_caller = chat_room.users.find { |u| u != current_user } # remember to update this later + puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>..HHHHHHHHH" + puts other_caller + puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>..HHHHHHHHH" + # redirect caller to chat room + ActionCable.server.broadcast('notifications', { + head: 302, # redirection code, just to make it clear what you're doing + path: chat_room_path(chat_room), # you'll need to use url_helpers, so include them in your file + body: { caller: other_caller.id } + } + # other_caller, # or however you identify your subscriber + ) + # redirect callee to chat room + redirect_to chat_room_path(chat_room) + # broadcast another message to caller + # head: 302 + + end end diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb new file mode 100644 index 0000000..ccb6cb8 --- /dev/null +++ b/app/controllers/requests_controller.rb @@ -0,0 +1,7 @@ +class RequestsController < ApplicationController + + def accept + + # Create new Chat Room + end +end diff --git a/app/javascript/packs/chatrooms.js b/app/javascript/packs/chatrooms.js new file mode 100644 index 0000000..46b193b --- /dev/null +++ b/app/javascript/packs/chatrooms.js @@ -0,0 +1,35 @@ +import ActionCable from 'actioncable' + +// create App object with key cable == new cosumer +(function() { + window.App || (window.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); + +// find chatroom id +const chatroomId = document.getElementById('chatroom-hook').dataset["chatroomId"] + +// create subsciptions +App['chatroom' + chatroomId] = App.cable.subscriptions.create({ + channel: 'ChatRoomsChannel', + room: chatroomId +}, { + connected: () => { + }, + received: data => { + } +}) + +// Testing ActionCable +const testBtn = document.getElementById('test-btn') +testBtn.addEventListener('click', event => { + fetch(`/chat_rooms/${chatroomId}/cable_testing` , { + method: 'POST', + body: JSON.stringify({}) + }) +}) + + + diff --git a/app/javascript/packs/notifications.js b/app/javascript/packs/notifications.js new file mode 100644 index 0000000..cff3892 --- /dev/null +++ b/app/javascript/packs/notifications.js @@ -0,0 +1,56 @@ +import ActionCable from 'actioncable' + +// create App object with key cable == new cosumer +(function() { + window.App || (window.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); + + +const userId = parseInt(document.getElementById("my-user-id").dataset["userId"]) +let chatRoomId = null + + +App.cable.subscriptions.create({ + channel: 'NotificationsChannel' +}, { + connected: () => { + console.log('Connected to NotificationsChannel') + }, + received: data => { + // console.log(data["message"]["user_id"]) + // console.log(userId) + console.log("received broadcast") + // console.log(data.body) + if (data.head === 302 && data.body["caller"] === userId && data.path ) { + window.location.pathname = data.path + } else if (data["message"]["user_id"] === userId) { + console.log("TRIGGER MODAL") + const acceptButton = document.getElementById('accept-button') + acceptButton.style.display = "block" + // const receiveCall = document.getElementById('receive-call') + // receiveCall.dataset.toggle = 'modal' + // receiveCall.dataset.target ='#calleeModal' + // console.log(receiveCall) + + // const calleeModal = document.getElementById('calleeModal') + // calleeModal.modal("show") + chatRoomId = data["message"]["chat_room_id"] + console.log(`user with id: ${userId} needs to subscribe to chatroom ${[chatRoomId]}`) + } else { + console.log(data) + } + + + } +}) + + +const acceptButton = document.getElementById('accept-button') + +acceptButton.addEventListener('click', event => { + // event.preventDefault() + document.getElementById('chat-room-id').value = chatRoomId +}) diff --git a/app/models/chat_room.rb b/app/models/chat_room.rb new file mode 100644 index 0000000..f4ac46b --- /dev/null +++ b/app/models/chat_room.rb @@ -0,0 +1,5 @@ +class ChatRoom < ApplicationRecord + has_many :chat_room_participations + has_many :users, through: :chat_room_participations + has_many :requests +end diff --git a/app/models/chat_room_participation.rb b/app/models/chat_room_participation.rb new file mode 100644 index 0000000..86931ec --- /dev/null +++ b/app/models/chat_room_participation.rb @@ -0,0 +1,4 @@ +class ChatRoomParticipation < ApplicationRecord + belongs_to :user + belongs_to :chat_room +end diff --git a/app/models/connection.rb b/app/models/connection.rb index 0028286..f66456a 100644 --- a/app/models/connection.rb +++ b/app/models/connection.rb @@ -8,7 +8,7 @@ class Connection < ApplicationRecord def create_inverted_connection unless Connection.where('user_id = ? and contact_id = ?', self.contact.id, self.user.id).length > 0 - Connection.create!(user: self.contact, contact: self.user) + inverted = Connection.create!(user: self.contact, contact: self.user) end end end diff --git a/app/models/request.rb b/app/models/request.rb new file mode 100644 index 0000000..2857ced --- /dev/null +++ b/app/models/request.rb @@ -0,0 +1,4 @@ +class Request < ApplicationRecord + belongs_to :user + belongs_to :chat_room +end diff --git a/app/models/user.rb b/app/models/user.rb index 265a42b..6043bee 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,9 @@ class User < ApplicationRecord :recoverable, :rememberable, :validatable has_many :connections + has_many :chat_room_participations + has_many :chat_rooms, through: :chat_room_participations + has_many :requests mount_uploader :photo, PhotoUploader diff --git a/app/views/chat_rooms/show.html.erb b/app/views/chat_rooms/show.html.erb new file mode 100644 index 0000000..0835cd4 --- /dev/null +++ b/app/views/chat_rooms/show.html.erb @@ -0,0 +1,27 @@ + + + +
+ + +
+
+
+ +
+
+
+ +
+ +
+ + + + +<%= javascript_pack_tag 'chatrooms' %> diff --git a/app/views/pages/_contact.html.erb b/app/views/pages/_contact.html.erb index 4c33e80..08f0a36 100644 --- a/app/views/pages/_contact.html.erb +++ b/app/views/pages/_contact.html.erb @@ -1,18 +1,30 @@ +<% +def hello_world + puts "Hello World" +end +%> +
-

FirstName LastName

+ <% if contact.nil? || contact.nil? %> +

<%= contact.email %>

+ <% else %> +

<%= contact.email %>

+ + <% end %>

Last call: <%= Time.now %>

-
- <%= link_to "#", 'data-toggle':"modal", 'data-target':"#myModal" do %> +
+ <%= link_to establish_call_path(contact.id), 'data-toggle':"modal", 'data-target':"#myModal" do %> <% end %>
+ diff --git a/app/views/pages/call.html.erb b/app/views/pages/call.html.erb index 700efaa..9776324 100644 --- a/app/views/pages/call.html.erb +++ b/app/views/pages/call.html.erb @@ -1,5 +1,5 @@ - + diff --git a/app/views/pages/index.html.erb b/app/views/pages/index.html.erb index 45289dd..a7c5547 100644 --- a/app/views/pages/index.html.erb +++ b/app/views/pages/index.html.erb @@ -2,8 +2,8 @@

Contacts

- <% 5.times do %> - <%= render "pages/contact" %> + <% current_user.contacts.each do |contact| %> + <%= render "pages/contact", contact: contact %> <% end %>
@@ -14,6 +14,13 @@
- +
+ +
+ + +
+ +<%= javascript_pack_tag 'notifications' %> diff --git a/config/environments/production.rb b/config/environments/production.rb index c90a719..8043aab 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -47,10 +47,10 @@ Rails.application.configure do # Mount Action Cable outside main process or domain # config.action_cable.mount_path = nil config.action_cable.url = 'wss://polyglot-173.herokuapp.com/cable' - config.action_cable.allowed_request_origins = [ '*' ] + config.action_cable.allowed_request_origins = [ 'https://polyglot-173.herokuapp.com/', 'https://www.polyglot.live' ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. diff --git a/config/routes.rb b/config/routes.rb index 6e91251..7a4cdbe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - get 'video_sessions/create' + devise_for :users, path: '', path_names: { sign_out: 'logout'} devise_scope :user do get '/logout', to: 'devise/sessions#destroy' @@ -15,10 +15,23 @@ Rails.application.routes.draw do get '/call', to: 'pages#call' + get '/establish_call/:contact_id', to: 'pages#establish_call', as: 'establish_call' + + post '/accept_call', to: 'pages#accept_call', as: 'accept_call/' + + patch '/accept_call/:request_id', to: 'requests#update', as: 'update_request' + get '/contacts', to: 'pages#index' get '/setting', to: 'users#setting' post '/sessions', to: 'video_sessions#create' + post '/chat_rooms/chat_room_sessions', to: 'chat_rooms#create' + + resources :chat_rooms, only: [ :show ] do + # testing action cable + post '/cable_testing', to: 'pages#cable_testing' + end + mount ActionCable.server, at: '/cable' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html get '/home', to: 'pages#home' diff --git a/db/migrate/20180829122818_create_chat_rooms.rb b/db/migrate/20180829122818_create_chat_rooms.rb new file mode 100644 index 0000000..a142563 --- /dev/null +++ b/db/migrate/20180829122818_create_chat_rooms.rb @@ -0,0 +1,8 @@ +class CreateChatRooms < ActiveRecord::Migration[5.2] + def change + create_table :chat_rooms do |t| + + t.timestamps + end + end +end diff --git a/db/migrate/20180829122930_create_chat_room_participations.rb b/db/migrate/20180829122930_create_chat_room_participations.rb new file mode 100644 index 0000000..34739cc --- /dev/null +++ b/db/migrate/20180829122930_create_chat_room_participations.rb @@ -0,0 +1,10 @@ +class CreateChatRoomParticipations < ActiveRecord::Migration[5.2] + def change + create_table :chat_room_participations do |t| + t.references :user, foreign_key: true + t.references :chat_room, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20180829123049_create_requests.rb b/db/migrate/20180829123049_create_requests.rb new file mode 100644 index 0000000..2417469 --- /dev/null +++ b/db/migrate/20180829123049_create_requests.rb @@ -0,0 +1,11 @@ +class CreateRequests < ActiveRecord::Migration[5.2] + def change + create_table :requests do |t| + t.references :user, foreign_key: true + t.references :chat_room, foreign_key: true + t.boolean :accepted + + t.timestamps + end + end +end diff --git a/db/migrate/20180829123204_change_column_in_requests.rb b/db/migrate/20180829123204_change_column_in_requests.rb new file mode 100644 index 0000000..87166c7 --- /dev/null +++ b/db/migrate/20180829123204_change_column_in_requests.rb @@ -0,0 +1,5 @@ +class ChangeColumnInRequests < ActiveRecord::Migration[5.2] + def change + change_column :requests, :accepted, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 2b17520..050711c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,11 +10,27 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_08_30_100110) do + +# ActiveRecord::Schema.define(version: 2018_08_30_100110) do +ActiveRecord::Schema.define(version: 2018_08_29_123204) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "chat_room_participations", force: :cascade do |t| + t.bigint "user_id" + t.bigint "chat_room_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["chat_room_id"], name: "index_chat_room_participations_on_chat_room_id" + t.index ["user_id"], name: "index_chat_room_participations_on_user_id" + end + + create_table "chat_rooms", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "connections", force: :cascade do |t| t.bigint "user_id" t.bigint "contact_id" @@ -22,6 +38,16 @@ ActiveRecord::Schema.define(version: 2018_08_30_100110) do t.index ["user_id"], name: "index_connections_on_user_id" end + create_table "requests", force: :cascade do |t| + t.bigint "user_id" + t.bigint "chat_room_id" + t.boolean "accepted", default: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["chat_room_id"], name: "index_requests_on_chat_room_id" + t.index ["user_id"], name: "index_requests_on_user_id" + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -41,6 +67,10 @@ ActiveRecord::Schema.define(version: 2018_08_30_100110) do t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + add_foreign_key "chat_room_participations", "chat_rooms" + add_foreign_key "chat_room_participations", "users" add_foreign_key "connections", "users" add_foreign_key "connections", "users", column: "contact_id" + add_foreign_key "requests", "chat_rooms" + add_foreign_key "requests", "users" end diff --git a/package.json b/package.json index 33c9f0a..4a85cda 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": true, "dependencies": { "@rails/webpacker": "3.5", + "actioncable": "^5.2.1", "bootstrap": "3", "jquery": "^3.3.1" }, diff --git a/test/controllers/chat_rooms_controller_test.rb b/test/controllers/chat_rooms_controller_test.rb new file mode 100644 index 0000000..5f545e2 --- /dev/null +++ b/test/controllers/chat_rooms_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ChatRoomsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/controllers/requests_controller_test.rb b/test/controllers/requests_controller_test.rb new file mode 100644 index 0000000..309c8e5 --- /dev/null +++ b/test/controllers/requests_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class RequestsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/models/chat_room_participation_test.rb b/test/models/chat_room_participation_test.rb new file mode 100644 index 0000000..fd70bc7 --- /dev/null +++ b/test/models/chat_room_participation_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ChatRoomParticipationTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/chat_room_test.rb b/test/models/chat_room_test.rb new file mode 100644 index 0000000..c621386 --- /dev/null +++ b/test/models/chat_room_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ChatRoomTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/request_test.rb b/test/models/request_test.rb new file mode 100644 index 0000000..f9f95ba --- /dev/null +++ b/test/models/request_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class RequestTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/yarn.lock b/yarn.lock index f8773a2..907dbe7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -57,6 +57,10 @@ acorn@^5.0.0: version "5.7.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.2.tgz#91fa871883485d06708800318404e72bfb26dcc5" +actioncable@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/actioncable/-/actioncable-5.2.1.tgz#615428a8a302cec55117d9049f0fd7952011c962" + ajv-keywords@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"