diff --git a/docker-compose.yml b/docker-compose.yml index 65d1d230..d6bd62bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,130 +1,130 @@ version: '3' services: coturn: container_name: kolab-coturn environment: - - DB_NAME=${OPENVIDU_COTURN_REDIS_DB} - - DB_PASSWORD=turn - - DEBUG=true - - MIN_PORT=57001 - - MAX_PORT=65535 + - DB_NAME=${OPENVIDU_COTURN_REDIS_DATABASE} + - DB_PASSWORD=${OPENVIDU_COTURN_REDIS_PASSWORD} - REDIS_IP=${OPENVIDU_COTURN_REDIS_IP} + - TURN_PUBLIC_IP=${OPENVIDU_COTURN_IP} - TURN_LISTEN_PORT=3478 hostname: sturn.mgmt.com image: openvidu/openvidu-coturn:1.0.0 network_mode: host restart: on-failure tty: true kolab: build: context: ./docker/kolab/ container_name: kolab depends_on: - mariadb extra_hosts: - "kolab.mgmt.com:127.0.0.1" healthcheck: interval: 10s test: test -f /tmp/kolab-init.done timeout: 5s retries: 30 hostname: kolab.mgmt.com image: kolab network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - /etc/letsencrypt/:/etc/letsencrypt/:ro - ./docker/certs/ca.cert:/etc/pki/tls/certs/ca.cert:ro - ./docker/certs/ca.cert:/etc/pki/ca-trust/source/anchors/ca.cert:ro - ./docker/certs/kolab.hosted.com.cert:/etc/pki/tls/certs/kolab.hosted.com.cert - ./docker/certs/kolab.hosted.com.key:/etc/pki/tls/certs/kolab.hosted.com.key - ./docker/certs/kolab.mgmt.com.cert:/etc/pki/tls/certs/kolab.mgmt.com.cert - ./docker/certs/kolab.mgmt.com.key:/etc/pki/tls/certs/kolab.mgmt.com.key - ./docker/kolab/utils:/root/utils:ro - ./src/.env:/.dockerenv:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro mariadb: container_name: kolab-mariadb environment: MYSQL_ROOT_PASSWORD: Welcome2KolabSystems healthcheck: interval: 10s test: test -e /var/run/mysqld/mysqld.sock timeout: 5s retries: 30 image: mariadb network_mode: host openvidu: container_name: kolab-openvidu environment: - APP_DOMAIN=${APP_DOMAIN} - - COTURN_IP=${OPENVIDU_PUBLIC_IP} - - COTURN_REDIS_DBNAME=2 - - COTURN_REDIS_IP=127.0.0.1 + - COTURN_IP=${OPENVIDU_COTURN_IP} + - COTURN_REDIS_DBNAME=${OPENVIDU_COTURN_REDIS_DATABASE} + - COTURN_REDIS_PASSWORD=${OPENVIDU_COTURN_REDIS_PASSWORD} + - COTURN_REDIS_IP=${OPENVIDU_COTURN_REDIS_IP} - HTTP_PORT=${OPENVIDU_SERVER_PORT} - - KMS_STUN_IP=${OPENVIDU_PUBLIC_IP} + - KMS_STUN_IP=${OPENVIDU_COTURN_IP} - KMS_STUN_PORT=3478 - - KMS_TURN_URL=openvidu:openvidu@${OPENVIDU_PUBLIC_IP} - KMS_URIS=["ws://localhost:8888/kurento"] - OPENVIDU_DOMAIN_OR_PUBLIC_IP=${OPENVIDU_PUBLIC_IP} - OPENVIDU_SECRET=${OPENVIDU_API_PASSWORD} + - OPENVIDU_WEBHOOK=${OPENVIDU_WEBHOOK} + - OPENVIDU_WEBHOOK_ENDPOINT=${OPENVIDU_WEBHOOK_ENDPOINT} - SERVER_PORT=${OPENVIDU_SERVER_PORT} - SERVER_SSL_ENABLED=false hostname: openvidu.hosted.com image: openvidu/openvidu-server-kms:2.13.0 network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true proxy: build: context: ./docker/proxy/ container_name: kolab-proxy hostname: kanarip.internet-box.ch image: kolab-proxy network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./docker/certs/:/etc/certs/:ro - /etc/letsencrypt/:/etc/letsencrypt/:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro redis: build: context: ./docker/redis/ container_name: kolab-redis hostname: redis image: redis network_mode: host volumes: - ./docker/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro worker: build: context: ./docker/worker/ container_name: kolab-worker depends_on: - kolab hostname: worker image: kolab-worker network_mode: host tmpfs: - /run - /tmp - /var/run - /var/tmp tty: true volumes: - ./src:/home/worker/src.orig:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro diff --git a/src/.env.example b/src/.env.example index a035dd1c..e9f79fb8 100644 --- a/src/.env.example +++ b/src/.env.example @@ -1,130 +1,132 @@ APP_NAME=Kolab APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://127.0.0.1:8000 APP_PUBLIC_URL= APP_DOMAIN=kolabnow.com SUPPORT_URL= LOG_CHANNEL=stack DB_CONNECTION=mysql DB_DATABASE=kolabdev DB_HOST=127.0.0.1 DB_PASSWORD=kolab DB_PORT=3306 DB_USERNAME=kolabdev BROADCAST_DRIVER=log CACHE_DRIVER=redis QUEUE_CONNECTION=redis SESSION_DRIVER=file SESSION_LIFETIME=120 2FA_DSN=mysql://roundcube:Welcome2KolabSystems@127.0.0.1/roundcube 2FA_TOTP_DIGITS=6 2FA_TOTP_INTERVAL=30 2FA_TOTP_DIGEST=sha1 IMAP_URI=ssl://127.0.0.1:993 IMAP_ADMIN_LOGIN=cyrus-admin IMAP_ADMIN_PASSWORD=Welcome2KolabSystems IMAP_VERIFY_HOST=false IMAP_VERIFY_PEER=false LDAP_BASE_DN="dc=mgmt,dc=com" LDAP_DOMAIN_BASE_DN="ou=Domains,dc=mgmt,dc=com" LDAP_HOSTS=127.0.0.1 LDAP_PORT=389 LDAP_SERVICE_BIND_DN="uid=kolab-service,ou=Special Users,dc=mgmt,dc=com" LDAP_SERVICE_BIND_PW="Welcome2KolabSystems" LDAP_USE_SSL=false LDAP_USE_TLS=false # Administrative LDAP_ADMIN_BIND_DN="cn=Directory Manager" LDAP_ADMIN_BIND_PW="Welcome2KolabSystems" LDAP_ADMIN_ROOT_DN="dc=mgmt,dc=com" # Hosted (public registration) LDAP_HOSTED_BIND_DN="uid=hosted-kolab-service,ou=Special Users,dc=mgmt,dc=com" LDAP_HOSTED_BIND_PW="Welcome2KolabSystems" LDAP_HOSTED_ROOT_DN="dc=hosted,dc=com" OPENVIDU_API_PASSWORD=MY_SECRET OPENVIDU_API_URL=http://localhost:8080/api/ OPENVIDU_API_USERNAME=OPENVIDUAPP OPENVIDU_API_VERIFY_TLS=true -OPENVIDU_COTURN_REDIS_DB=2 +OPENVIDU_COTURN_IP=127.0.0.1 +OPENVIDU_COTURN_REDIS_DATABASE=2 OPENVIDU_COTURN_REDIS_IP=127.0.0.1 +OPENVIDU_COTURN_REDIS_PASSWORD=turn # Used as COTURN_IP, TURN_PUBLIC_IP, for KMS_TURN_URL OPENVIDU_PUBLIC_IP=127.0.0.1 OPENVIDU_PUBLIC_PORT=3478 OPENVIDU_SERVER_PORT=8080 OPENVIDU_WEBHOOK=true OPENVIDU_WEBHOOK_ENDPOINT=http://127.0.0.1:8000/webhooks/meet/openvidu # "CDR" events, see https://docs.openvidu.io/en/2.13.0/reference-docs/openvidu-server-cdr/ #OPENVIDU_WEBHOOK_EVENTS=[sessionCreated,sessionDestroyed,participantJoined,participantLeft,webrtcConnectionCreated,webrtcConnectionDestroyed,recordingStatusChanged,filterEventDispatched,mediaNodeStatusChanged] #OPENVIDU_WEBHOOK_HEADERS=[\"Authorization:\ Basic\ SOMETHING\"] REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 SWOOLE_HTTP_HOST=127.0.0.1 SWOOLE_HTTP_PORT=8000 PAYMENT_PROVIDER= MOLLIE_KEY= STRIPE_KEY= STRIPE_PUBLIC_KEY= STRIPE_WEBHOOK_SECRET= MAIL_DRIVER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS="noreply@example.com" MAIL_FROM_NAME="Example.com" MAIL_REPLYTO_ADDRESS=null MAIL_REPLYTO_NAME=null DNS_TTL=3600 DNS_SPF="v=spf1 mx -all" DNS_STATIC="%s. MX 10 ext-mx01.mykolab.com." DNS_COPY_FROM=null AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" JWT_SECRET= COMPANY_NAME= COMPANY_ADDRESS= COMPANY_DETAILS= COMPANY_EMAIL= COMPANY_LOGO= COMPANY_FOOTER= VAT_COUNTRIES=CH,LI VAT_RATE=7.7 KB_ACCOUNT_DELETE= KB_ACCOUNT_SUSPENDED= diff --git a/src/resources/js/meet/app.js b/src/resources/js/meet/app.js index cd47d3c8..3402a1e7 100644 --- a/src/resources/js/meet/app.js +++ b/src/resources/js/meet/app.js @@ -1,176 +1,177 @@ import { OpenVidu } from 'openvidu-browser' -function Meet(container, config) +//function Meet(container, config) +function Meet(container) { let OV // OpenVidu object to initialize a session let session // Session object where the user will connect let publisher // Publisher object which the user will publish let sessionId // Unique identifier of the session let audioEnabled = true // True if the audio track of publisher is active let videoEnabled = true // True if the video track of publisher is active let numOfVideos = 0 // Keeps track of the number of videos that are being shown $(container).append('
') OV = new OpenVidu() - OV.setAdvancedConfiguration(config) + //OV.setAdvancedConfiguration(config) // Disconnect participant on browser's window closed /* window.addEventListener('beforeunload', () => { if (session) session.disconnect(); }) */ // Public methods this.joinRoom = joinRoom function joinRoom(data) { sessionId = data.session // Init a session session = OV.initSession() // On every new Stream received... session.on('streamCreated', function (event) { // Subscribe to the Stream to receive it. HTML video will be appended to element with 'subscriber' id var subscriber = session.subscribe(event.stream, 'videos'); // When the new video is added to DOM, update the page layout to fit one more participant subscriber.on('videoElementCreated', (event) => { numOfVideos++ updateLayout() }) }) // On every new Stream destroyed... session.on('streamDestroyed', (event) => { // Update the page layout numOfVideos-- updateLayout() }) // Connect with the token session.connect(data.token) .then(() => { // Update the URL shown in the browser's navigation bar to show the session id ///var path = (location.pathname.slice(-1) == "/" ? location.pathname : location.pathname + "/"); ///window.history.pushState("", "", path + '#' + sessionId); // Auxiliary methods to show the session's view //showSessionHideJoin() // Get the camera stream with the desired properties publisher = OV.initPublisher('videos', { audioSource: undefined, // The source of audio. If undefined default audio input videoSource: undefined, // The source of video. If undefined default video input publishAudio: true, // Whether to start publishing with your audio unmuted or not publishVideo: true, // Whether to start publishing with your video enabled or not resolution: '640x480', // The resolution of your video frameRate: 30, // The frame rate of your video insertMode: 'PREPEND', // How the video is inserted in target element 'video-container' mirror: true // Whether to mirror your local video or not }) // When our HTML video has been added to DOM... publisher.on('videoElementCreated', (event) => { // When your own video is added to DOM, update the page layout to fit it numOfVideos++ updateLayout() $(event.element).prop('muted', true) // Mute local video to avoid feedback }) // Publish the stream session.publish(publisher) }) .catch(error => { console.log('There was an error connecting to the session:', error.code, error.message); }) } function leaveRoom() { // Leave the session by calling 'disconnect' method over the Session object session.disconnect(); } function muteAudio() { audioEnabled = !audioEnabled publisher.publishAudio(audioEnabled) if (!audioEnabled) { $('#mute-audio').removeClass('btn-primary') $('#mute-audio').addClass('btn-default') } else { $('#mute-audio').addClass('btn-primary') $('#mute-audio').removeClass('btn-default') } } function muteVideo() { videoEnabled = !videoEnabled publisher.publishVideo(videoEnabled) if (!videoEnabled) { $('#mute-video').removeClass('btn-primary') $('#mute-video').addClass('btn-default') } else { $('#mute-video').addClass('btn-primary') $('#mute-video').removeClass('btn-default') } } // 'Session' page function showSessionHideJoin() { $('#nav-join').hide() $('#nav-session').show() $('#join').hide() $('#session').show() $('footer').hide() $('#main-container').removeClass('container') } // 'Join' page function showJoinHideSession() { $('#nav-join').show() $('#nav-session').hide() $('#join').show() $('#session').hide() $('footer').show() $('#main-container').addClass('container') } // Dynamic layout adjustemnt depending on number of videos function updateLayout() { console.warn('There are now ' + numOfVideos + ' videos') var publisherDiv = $('#publisher') var publisherVideo = $("#publisher video") var subscriberVideos = $('#videos > video') switch (numOfVideos) { case 1: publisherVideo.addClass('video1') break case 2: publisherDiv.addClass('video2') subscriberVideos.addClass('video2') break case 3: publisherDiv.addClass('video3') subscriberVideos.addClass('video3') break case 4: publisherDiv.addClass('video4') publisherVideo.addClass('video4') subscriberVideos.addClass('video4') break default: publisherDiv.addClass('videoMore') publisherVideo.addClass('videoMore') subscriberVideos.addClass('videoMore') break } } } export default Meet diff --git a/src/resources/vue/Meet/Room.vue b/src/resources/vue/Meet/Room.vue index 56ae896f..4c5a2a57 100644 --- a/src/resources/vue/Meet/Room.vue +++ b/src/resources/vue/Meet/Room.vue @@ -1,47 +1,49 @@