book reading PoC

This commit is contained in:
Sagi Dayan 2020-04-13 20:56:04 -04:00
parent 21ef1e25b2
commit 74ed7612d6
14 changed files with 144 additions and 23 deletions

View file

@ -45,6 +45,10 @@ class ClientApiController {
return child;
}
async getBooks() {}
async getCallBooks() {}
async createCall({auth, request, response}) {
try {
const user = auth.user;

View file

@ -93,6 +93,8 @@ class CallSession {
socket.on('wrtc:sdp:offer', this.onSdpOffer.bind(this));
socket.on('wrtc:sdp:answer', this.onSdpAnswer.bind(this));
socket.on('wrtc:ice', this.onIceCandidate.bind(this));
socket
.on('book:action:flip-page', this.onActionBookFlip.bind(this))
await this.updateState();
if (this.state === 'STARTED') {
await this.sendStandby(socket, userIndex);
@ -160,14 +162,14 @@ class CallSession {
const {from = payload.id, ice} = payload;
const to = from === 1 ? 2 : 1;
this[`user_${to}`].socket.emit('wrtc:ice', {ice});
console.log(`[Signal] [onIceCandidate] ${from} -> ${to}`)
console.log(`[Signal] [onIceCandidate] ${from} -> ${to}`);
return true;
}
async onSdpOffer(payload) {
const {from = payload.id, sdp} = payload;
const to = from === 1 ? 2 : 1;
this[`user_${to}`].socket.emit('wrtc:sdp:offer', {sdp});
console.log(`[Signal] [onSdpOffer] ${from} -> ${to}`)
console.log(`[Signal] [onSdpOffer] ${from} -> ${to}`);
return true;
}
@ -175,7 +177,16 @@ class CallSession {
const {from = payload.id, sdp} = payload;
const to = from === 1 ? 2 : 1;
this[`user_${to}`].socket.emit('wrtc:sdp:answer', {sdp});
console.log(`[Signal] [onSdpAnswer] ${from} -> ${to}`)
console.log(`[Signal] [onSdpAnswer] ${from} -> ${to}`);
return true;
}
onActionBookFlip(payload) {
const {from = payload.id, direction} = payload;
const to = from === 1 ? 2 : 1;
this[`user_${to}`].socket.emit('book:action:flip-page', {direction});
console.log(
`[Signal] [book] [action] [flip] [${direction}] ${from} -> ${to}`);
return true;
}
}

12
app/Models/Book.js Normal file
View file

@ -0,0 +1,12 @@
'use strict'
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')
class Book extends Model {
user() {
return this.belongsTo('App/Models/User');
}
}
module.exports = Book

View file

@ -0,0 +1,22 @@
'use strict'
/** @type {import('@adonisjs/lucid/src/Schema')} */
const Schema = use('Schema')
class BookSchema extends Schema {
up() {
this.create('books', (table) => {
table.increments()
table.bigInteger('user_id').notNullable();
table.integer('pages').notNullable();
table.string('book_folder').notNullable();
table.timestamps()
})
}
down() {
this.drop('books')
}
}
module.exports = BookSchema

View file

@ -39,6 +39,7 @@
"adonis-vue-websocket": "^2.0.2",
"animate.css": "^3.7.2",
"bulma": "^0.8.0",
"flipbook-vue": "^0.8.1",
"fork-awesome": "^1.1.7",
"moment": "^2.24.0",
"regenerator-runtime": "^0.13.5",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -6914,3 +6914,7 @@ label.panel-block {
opacity: 0; }
100% {
opacity: 1; } }
.flipbook {
width: 100%;
height: 60vh; }

View file

@ -223,3 +223,8 @@ $positions: (
opacity: 1;
}
}
// TODO: Remove this - make generic
.flipbook {
width: 100%;
height: 60vh;
}

View file

@ -2,7 +2,7 @@ import WebSocketService from "../scripts/websocket.service";
import { EventEmitter } from "events";
export default class CallManager {
private inCall: boolean;
private peerId: number;
public peerId: number;
private localStream: MediaStream;
private remoteStream: MediaStream;
private signalingChannel;
@ -16,6 +16,7 @@ export default class CallManager {
this.remoteStream = new MediaStream();
}
async connectToCall(mediaConstraints: MediaStreamConstraints): Promise<boolean> {
if (this.inCall) throw new Error('Already connected to call');
console.log('connecting to call');
@ -30,6 +31,7 @@ export default class CallManager {
signalingChannel.on('wrtc:sdp:offer', self.onRemoteOffer.bind(self));
signalingChannel.on('wrtc:sdp:answer', self.onRemoteAnswer.bind(self));
signalingChannel.on('wrtc:ice', self.onRemoteIce.bind(self));
signalingChannel.on('book:action:flip-page', self.onActionBookFlip.bind(self))
signalingChannel.on('error', (e) => {
console.error(e);
resolve(false)
@ -150,6 +152,10 @@ export default class CallManager {
return this.remoteStream;
}
onActionBookFlip(payload) {
this.emit(ECallEvents.ACTION_BOOK_FLIP, payload);
};
close() {
console.log('Closing...');
if (!this.inCall) return;
@ -162,9 +168,11 @@ export default class CallManager {
this.remoteStream = null;
this.inCall = false;
}
}
export enum ECallEvents {
CLOSE = 'CLOSE',
REMOTE_STREAM = 'REMOTE_STREAM'
REMOTE_STREAM = 'REMOTE_STREAM',
ACTION_BOOK_FLIP = 'ACTION_BOOK_FLIP'
}

View file

@ -3,7 +3,8 @@
<div v-if="loading">
<Loading />
</div>
<div v-else class="is-flex">
<div v-else class>
<div class="video-strip is-flex">
<video
:src-object.prop.camel="localStream"
autoplay
@ -13,6 +14,18 @@
/>
<video :src-object.prop.camel="remoteStream" autoplay style="max-width:40%" />
</div>
<div class>
<flipbook
class="flipbook"
:pages="createPages(book)"
forwardDirection="left"
:zooms="null"
@flip-left-end="onFlip('left')"
@flip-right-end="onFlip('right')"
ref="flipbook"
></flipbook>
</div>
</div>
</div>
</template>
@ -20,11 +33,13 @@
import Loading from "../../shared/components/Loading/Loading.vue";
import WebsocketService from "../scripts/websocket.service";
import CallManager, { ECallEvents } from "../classes/call.manager";
import Flipbook from "flipbook-vue";
import Services from "../../services/index";
import { mapActions, mapGetters } from "vuex";
export default {
components: {
Loading
Loading,
Flipbook
},
name: "Call",
@ -35,6 +50,7 @@ export default {
const ws = await WebsocketService.getInstance();
this.callManager = new CallManager(ws, callId);
this.callManager.on(ECallEvents.CLOSE, this.callEnded);
this.callManager.on(ECallEvents.ACTION_BOOK_FLIP, this.onRemoteFlip);
const success = await this.callManager.connectToCall({
video: true,
audio: true
@ -63,6 +79,27 @@ export default {
async setupCall(): Promise<boolean> {
return true;
},
onFlip(direction: "left" | "right") {
if (this.callManager.peerId == 2)
this.callManager.send(`book:action:flip-page`, { direction });
},
onRemoteFlip(payload) {
switch (payload.direction) {
case "left":
this.$refs.flipbook.flipLeft();
break;
case "right":
this.$refs.flipbook.flipRight();
break;
}
},
createPages(book) {
const pages = [null];
for (let i = 1; i < book.pages + 1; i++) {
pages.push(`/u/images/${i}.JPG`);
}
return pages;
},
callEnded(callId) {
this.notify({ message: `Call #${callId} Ended` });
this.$router.push({ path: `/` });
@ -74,6 +111,10 @@ export default {
},
data() {
return {
book: {
title: "Taylor",
pages: 34
},
loading: true,
localStream: null,
remoteStream: null,
@ -84,3 +125,4 @@ export default {
};
</script>

View file

@ -3142,6 +3142,13 @@ flagged-respawn@^1.0.0:
resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
flipbook-vue@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/flipbook-vue/-/flipbook-vue-0.8.1.tgz#1b3d29a5a8d0d6921ff0be1a91e4165b0d9d6d6e"
integrity sha512-HPWrGe6fwIGSG2IV+kN2Bz16pp8DtsgvNrObxaXtr+XNwxgaLWpbKzM8QV5alBcMFJtyo+7d2Ds1zLrCp8h1LQ==
dependencies:
rematrix "^0.4.1"
flush-write-stream@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
@ -5993,6 +6000,11 @@ regjsparser@^0.1.4:
dependencies:
jsesc "~0.5.0"
rematrix@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/rematrix/-/rematrix-0.4.1.tgz#496d40b48c79dd3820bc40352b8d7bec44b32887"
integrity sha512-nH4OjL09zw4yhdBClK4B93kRWbHu+std7ZV6ljS2Zsgy2YrPcayL67axKLfMxoFool8mPyVY614m8SFE7sJQLw==
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"