続いてオブジェクトを作っていきます
合成
切り抜きも出来る
ロック
雨雲
もはや職人の世界だな、これ。。
随机应变 ABCD: Always Be Coding and … : хороший
続いてオブジェクトを作っていきます
合成
切り抜きも出来る
ロック
雨雲
もはや職人の世界だな、これ。。
復習します
まず設定から
オブジェクトを書いていきます。
色の設定
なるほど♬♪
firewallを超える場合に、turnサーバーでドメインを指定する
$ sudo cp /usr/local/etc/turnserver.conf.default /usr/local/etc/turnserver.conf
$ sudo vi /usr/local/etc/turnserver.conf
# The default realm to be used for the users when no explicit # origin/realm relationship was found in the database, or if the TURN # server is not using any database (just the commands-line settings # and the userdb file). Must be used with long-term credentials # mechanism or with TURN REST API. # #realm=mycompany.org ... # Uncomment if no UDP client listener is desired. # By default UDP client listener is always started. # #no-udp # Uncomment if no TCP client listener is desired. # By default TCP client listener is always started. # #no-tcp # Uncomment if no TLS client listener is desired. # By default TLS client listener is always started. # #no-tls # Uncomment if no DTLS client listener is desired. # By default DTLS client listener is always started. # #no-dtls
ってことはSTUNは外部で調達して、TURNはインスタンスで立てるって理解でOK?
WebRTC通信
– Peer to Peer、ブラウザ間で直接通信
– UDP/IPを使用、オーバーヘッドが少ない
– 鍵交換で暗号化通信を行う
-> 相手のIPアドレス、動的なUDPポート番号を知る必要がある
-> 通信経路の仕組みがInteractive Connectivity Establishment、その候補がICE Candidate
–> NATを通過するためのSTUNサーバから取得したポートマッピング
–> Firewallを越えるための、TURNによるリレーサーバーを介した中継通信
–> このやりとりをシグナリングと言う。WebSocketなど複数の方法がある
-> 複数人通信の場合には、それぞれのユーザとSDP/IPのconnectionをつくる必要がある
NATとは
グローバルIPとローカルのネットワークIPとの変換
複数のPC/デバイスが同時に通信できるよう、ポートマッピングによるポート変換
→ブラウザはローカルのIP、UDPポートはわかるが、グローバルのIP、UDPはわからない
→→Peer to Peerはグローバルの情報を交換する必要がある
STUN(Session Traversal Utilities for NATs)
NATで変換されたIP/UDPを外のSTUNサーバーから教えてもらう
→グローバル情報をシグナリングサーバーけいゆうで相手に渡す
STUNサーバーはGoogleのstun.l.google.com:19302など
TURN(Traversal Using Relays around NAT)
ストリームデータの受け渡しにリレーする
TURNサーバが入ると厳密にはPeer to Peerではなくなる
データのデコード、エンコードは行わないので、ネットワーク負荷が高くなる
あれ、Bitcoinって、P2Pだけど、STAN, TURN使ってるんだっけ?
否、BitcoinはTCP😂
ローカル環境で、httpsの挙動を確認したい時に使えるのが、hyper-builtinというライブラリ
https://github.com/mpyw/php-hyper-builtin-server
opensslでサーバー証明書を生成し、composerでhyper-builtinを入れて起動
※下はawslinuxだが、centosでも同様
### sslモジュールインストール(centOSの場合はmod_ssl)
$ sudo yum install mod24_ssl
$ httpd -M | grep ssl
### 秘密鍵作成
$ openssl genrsa > server.key
### CSR作成
$ openssl req -new -key server.key > server.csr
### サーバー証明書作成
$ openssl x509 -req -signkey server.key < server.csr > server.crt
$ rm server.csr
### 秘密鍵&サーバー証明書配置
$ sudo mkdir /etc/httpd/conf/ssl.key
$ sudo mkdir /etc/httpd/conf/ssl.crt
$ sudo mv server.key /etc/httpd/conf/ssl.key/
$ sudo mv server.crt /etc/httpd/conf/ssl.crt/
### ssl.conf編集
sudo vi /etc/httpd/conf.d/ssl.conf
# SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateFile /etc/httpd/conf/ssl.crt/server.crt
# SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateKeyFile /etc/httpd/conf/ssl.key/server.key
### apache再起動
$ sudo service httpd restart
### composerでhttps用のphp buildin-server libraryインストール
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require –dev mpyw/php-hyper-builtin-server:^2.0
### httpsサーバー起動
$ vendor/bin/hyper-run -s 192.168.33.10:8000
うおおおおおおおおおおおおおお、めんどくせええええええええええええ
これ、playbook.ymlで一括管理してーーーーーーーーーーーーー
まず、WebRTCとは?
-WebReal-Time Communicationsの略
-ウェブでシンプルなAPI経由でリアルタイム通信を提供する
-P2P通信
-オープンソース
アーキテクチャ
セッションでやりとりしてるんか。。
-getUserMedia
ブラウザから端末に取り付けられているカメラやマイクにアクセスしてストリームデータを取得
-RTCPeerConnection
マルチメディアセッションを確立するAPI
-RTCDataChannel
テキストデータ、バイナリデータのP2Pデータ通信API
vagrant でvideoのテスト
<!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Wrap old and new getUserMedia</title> </head> <body> Wrap old and new getUserMedia<br /> <button type="button" onclick="startVideo();">Start</button> <button type="button" onclick="stopVideo();">Stop</button> <br /> <video id="local_video" autoplay style="width: 320px; height: 240px; border: 1px solid black;"></video> </body> <script type="text/javascript"> var localVideo = document.getElementById('local_video'); var localStream = null; // --- prefix ----- navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; // ---------------------- video handling ----------------------- // start local video function startVideo() { getDeviceStream({video: true, audio: false}) .then(function (stream) { // success localStream = stream; playVideo(localVideo, stream); }).catch(function (error) { // error console.error('getUserMedia error:', error); return; }); } // stop local video function stopVideo() { pauseVideo(localVideo); stopLocalStream(localStream); } function stopLocalStream(stream) { let tracks = stream.getTracks(); if (! tracks) { console.warn('NO tracks'); return; } for (let track of tracks) { track.stop(); } } function getDeviceStream(option) { if ('getUserMedia' in navigator.mediaDevices) { console.log('navigator.mediaDevices.getUserMadia'); return navigator.mediaDevices.getUserMedia(option); } else { console.log('wrap navigator.getUserMadia with Promise'); return new Promise(function(resolve, reject){ navigator.getUserMedia(option, resolve, reject ); }); } } function playVideo(element, stream) { if ('srcObject' in element) { element.srcObject = stream; } else { element.src = window.URL.createObjectURL(stream); } element.play(); element.volume = 0; } function pauseVideo(element) { element.pause(); if ('srcObject' in element) { element.srcObject = null; } else { if (element.src && (element.src !== '') ) { window.URL.revokeObjectURL(element.src); } element.src = ''; } } </script> </html>
built in
[vagrant@localhost webrtc]$ php -S 192.168.33.10:8000
あれ?
なに、みれないぞ。。
ソースコードがおかしいか?
同じソースコードで、*.github.ioにcommitして確認
=> 見れる
なにいいいいいいいいいいいいいいいいいいいいい
server側の設定か?
そんなばかな。。。
=> 2時間くらい調査
=> 少し疲れたので休憩
=> あれ、videoタグの設定か?
=> chromeのカメラの設定を確認
httpだと、カメラのアクセスがブロックされるのね。。。
amazon linuxにmod-sslを入れます。
[vagrant@localhost webrtc]$ sudo yum install -y mod_ssl
–> Finished Dependency Resolution
Error: httpd24 conflicts with httpd-2.2.34-1.15.amzn1.x86_64
Error: httpd24-tools conflicts with httpd-tools-2.2.34-1.15.amzn1.x86_64
ぎゃああああああああああああああああああああああ
[vagrant@localhost webrtc]$ sudo yum install mod24_ssl
Complete!
もうやだ。
tableの入力画面で、例えばradioボタンの選択状況によって、下のtr要素の表示・非表示を変えたいとする
<table> <tr> <th> hpscript </th> <td> <input type="radio" name="a" value="y" checked>yes <input type="radio" name="a" value="n">no </td> </tr> <tr> <th> タイトル1 </th> <td> コンテンツ1 </td> </tr> </table>
これをVue.jsのv-on:${}で実装しようとしたが、上手く行かない
<table> <div id="app"> <tr> <th> hpscript </th> <td> <input type="radio" name="a" v-on:change="handler" value="y" checked>yes <input type="radio" name="a" v-on:change="handler" value="n">no </td> </tr> <div v-if="show"> <tr> <th> タイトル1 </th> <td> コンテンツ1 </td> </tr> </div> </div> </table> <script> new Vue({ el: '#app', data: { show: true }, methods: { handler: function(event){ if(event.target.value === 'y'){ this.show = true } else { this.show = false } } } }) </script>
ガッテム。結局、on.changeで実装することに。
<table> <tr> <th> hpscript </th> <td> <input type="radio" name="a" value="y" checked>yes <input type="radio" name="a" value="n">no </td> </tr> <tr class="changeterm displaynone"> <th> タイトル1 </th> <td> コンテンツ1 </td> </tr> </table> <script> $('input[name=a]').on('change', function(){ if($('.changeterm').hasClass('displaynone')){ $('.changeterm').removeClass('displaynone'); } else { $('.changeterm').addClass('displaynone'); } }); </script>
.displaynone { display:none; }
なんでtableでVue.jsのv-onだと上手く行かないのかよくわからない。。
教えて欲しい。。🤖
v-ifで、trueだった場合に、v-model.trimで文字数をカウントしたい場合。
v-ifの中にv-model.trimが入っているので、いわゆるネスト
この場合、new Vueを続けて書いてもうまく行かない
<div id="app"> <div v-if="display"> <div id="job"> <input type="text" name="title" v-model.trim="message" maxlength="20" placeholder="20文字以内で入力してください"> <span class="char-length">{{ message.length }}/20</span> </div> </div> <div v-else> <p>表示なし</p> </div> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> new Vue({ el: "#app", data: { display: true } }); new Vue({ el: "#job", data: { message: "what up bro!"} }); </script>
どうするかというと、子供のインスタンスのidに”v-pre”をつける
<div id="job" v-pre> <input type="text" name="title" v-model.trim="message" maxlength="20" placeholder="20文字以内で入力してください"> <span class="char-length">{{ message.length }}/20</span> </div>
すると、上手く表示されます。
嵌ったー、15分くらい😱
npm install -D prettier gulp-prettier-plugin
var gulp = require('gulp'); var prettierPlugin = require('gulp-prettier-plugin'); var imagemin = require('gulp-imagemin'); var sass = require('gulp-sass'); var sassLint = require('gulp-sass-lint'); var eslint = require('gulp-eslint'); var plumber = require('gulp-plumber'); var webserver = require('gulp-webserver'); gulp.task('prettier', function(done){ gulp.src(['./src/sass/*.scss','./src/*.js']) .pipe(prettierPlugin({ prettier:{ singleQuote:true }, },{filter: true})) .pipe(gulp.dest(file => file.base)) done(); }); gulp.task('html', function(done){ gulp.src('./src/*.html') .pipe(gulp.dest('./dest')) done(); }); gulp.task('img', function(done){ gulp.src('./src/img/*.png') .pipe(imagemin()) .pipe(gulp.dest('./dest/img')) done(); }); gulp.task('sass', function(done){ gulp.src('./src/sass/*.scss') .pipe(plumber()) .pipe(sassLint()) .pipe(sassLint.format()) .pipe(sassLint.failOnError()) .pipe(sass({outputStyle: 'expand'})) .pipe(gulp.dest('./dest/css')) done(); }); gulp.task('js', function(done){ gulp.src(['./src/*.js','!node_modules/**']) .pipe(plumber()) .pipe(eslint({ useEslintrc: true })) .pipe(eslint.format()) .pipe(eslint.failAfterError()) .pipe(gulp.dest('./dest/js')) done(); }); gulp.task('watch', function(done){ gulp.watch('./src/*.html', gulp.task('html')) gulp.watch('./src/js/*.html', gulp.task('js')) gulp.watch('./src/sass/*.scss', gulp.task('sass')) done(); }); gulp.task('webserver', function(done){ gulp.src('./dest') .pipe(webserver({ host:'192.168.34.10', port: 8000, livereload: true, })); done(); }); gulp.task('default', gulp.series('prettier','html','js','img','sass','watch','webserver'));
とりあえず、環境構築はこんなところか。
さー、front書き始めましょうかね^^
$ npm i -D gulp-eslint
var gulp = require('gulp'); var imagemin = require('gulp-imagemin'); var webserver = require('gulp-webserver'); var sass = require('gulp-sass'); var sassLint = require('gulp-sass-lint'); var eslint = require('gulp-eslint'); var plumber = require('gulp-plumber'); gulp.task('html', function(done){ gulp.src('./src/*.html') .pipe(gulp.dest('./dest')) done(); }); gulp.task('js', function(done){ gulp.src(['./src/*.js','!node_modules/**']) .pipe(eslint({ useEslintrc: true })) .pipe(eslint.format()) .pipe(eslint.failAfterError()) .pipe(gulp.dest('./dest/js')) done(); }); gulp.task('img', function(done){ gulp.src('./src/img/*.png') .pipe(imagemin()) .pipe(gulp.dest('./dest/img')) done(); }); gulp.task('sass', function(done){ gulp.src('./src/sass/*.scss') .pipe(plumber()) .pipe(sassLint()) .pipe(sassLint.format()) .pipe(sassLint.failOnError()) .pipe(sass({outputStyle: 'expand'})) .pipe(gulp.dest('./dest/css')) done(); }); gulp.task('watch', function(done){ gulp.watch('./src/*.html', gulp.task('html')) gulp.watch('./src/js/*.html', gulp.task('js')) gulp.watch('./src/sass/*.scss', gulp.task('sass')) done(); }); gulp.task('webserver', function(done){ gulp.src('./dest') .pipe(webserver({ host:'192.168.34.10', port: 8000, livereload: true, })); done(); }); gulp.task('default', gulp.series('html','js','img','sass','watch','webserver'));