Ruby on RailsでRedisのLIST操作
RailsでRedisのLIST型操作のコード例が見当たらなかったので備忘録
rpush, lpush で追加
lrange で取得
lrem, rpop, lpop で削除
ドキュメントhttps://www.rubydoc.info/github/redis/redis-rb/Redis
前提
Gemfileに追記
gem 'redis'
予めRedisインスタンスをnewしておく
REDIS = Redis.new
rpushで追加
REDIS.rpush("hogelist", "item-a")
>["item-a"]
REDIS.rpush("hogelist", "item-b")
REDIS.rpush("hogelist", "item-c")
>["item-a", "item-b", "item-c"]
配列でまとめて追加もできる
REDIS.rpush("hogelist", ["item-d","item-d","item-d"])
>["item-a", "item-b", "item-c", "item-d", "item-d", "item-d"]
lpushで先頭に追加できる
REDIS.lpush("hogelist", "item-X")
REDIS.lpush("hogelist", ["item-Y","item-Y"])
>["item-Y", "item-Y", "item-X", "item-a", "item-b", "item-c", "item-d", "item-d", "item-d"]
lrangeで取得
REDIS.lrange("hogelist", 0, -1)
>["item-Y", "item-Y", "item-X", "item-a", "item-b", "item-c", "item-d", "item-d", "item-d"]
第二、第三引数で配列インデックスを指定することで部分取得できる。
REDIS.lrange("hogelist", 0, 0)
>["item-Y"]
REDIS.lrange("hogelist", 0, 3)
>["item-Y", "item-Y", "item-X", "item-a"]
REDIS.lrange("hogelist", 3, 3)
>["item-a"]
※インデックスが不正だと空になる
REDIS.lrange("hogelist", 3, 2)
>
※通常のgetだとエラーになる
REDIS.get("hogelist")
削除
delでLIST全削除
REDIS.del("hogelist")
>
部分削除
元:["item-Z", "item-Y", "item-Y", "item-X", "item-a", "item-Z", "item-b", "item-c", "item-d", "item-d", "item-d", "item-Z"]から
値を指定して削除
REDIS.lrem("hogelist", 0, "item-Z")
>["item-Y", "item-Y", "item-X", "item-a", "item-b", "item-c", "item-d", "item-d", "item-d"]
第二引数で削除数を指定 ※上のように0で全部
REDIS.lrem("hogelist", 2, "item-d")
>["item-Y", "item-Y", "item-X", "item-a", "item-b", "item-c", "item-d"]
※実際にある数より多くてもエラーにはならない
REDIS.lrem("hogelist", 3, "item-b")
>["item-Y", "item-Y", "item-X", "item-a", "item-c", "item-d", "item-d", "item-d"]
rpopで末尾削除
REDIS.rpop("hogelist")
>["item-Y", "item-Y", "item-X", "item-a", "item-c", "item-d", "item-d"]
lpopで先頭削除
REDIS.lpop("hogelist")
>["item-Y", "item-X", "item-a", "item-c", "item-d", "item-d"]
gRPCをdockerで動かしたぜんぜんわからんからメモ
gRPCを学ぼうとしているけどぜんぜんわからん
まずGo言語もわからん
プロトコルバッファーもわからん
まともに動かすのも難儀する
下記URLを参考にひとまず動くものを手にしようと思ってもうまくいかなかったり四苦八苦したので、Bidirectional streaming RPC を動かしたメモを残す
goでgRPCの4つの通信方式やってみた(Dockerのサンプルあり) - Qiita
詰まったポイントとしては、protoファイルに option go_package の記述がないことでエラーになったことの対処だったり、
Dockerにてホスト側の作業ディレクトリの親の親ディレクトリをボリュームマウントすることで不要なファイルまでマウントしてので、作業ディレクトリ配下で完結するようにしたり、
あとコンテナに入らないでコマンド実行する方法をまとめた。
環境
・win10 vbox Ubuntu
・docker、docker-compose インストール済
準備
ホスト側作業ディレクトリ
/var/docker/grpc-docker
ファイル・フォルダ構成
./docker-compose.yml
./grpc/Dockerfile
./grpc/src/proto/chat.proto
./grpc/src/server/main.go
./grpc/src/client/main.go
./grpc/src/pb/chat ※空フォルダ
./docker-compose.yml
version: "3.7"
services:
go-grpc:
build:
context: ./grpc/
dockerfile: Dockerfile
container_name: "grpc"
volumes:
- ./grpc/src/:/go-grpc
tty: true
privileged: true
./grpc/Dockerfile
FROM golang:1.13-stretch
SHELL ["/bin/bash", "-c"]
RUN apt update && apt-get install -y vim unzip# install protc
WORKDIR /protoc
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v3.11.2/protoc-3.11.2-linux-x86_64.zip
RUN unzip protoc-3.11.2-linux-x86_64.zip
RUN ln -s /protoc/bin/protoc /bin/protoc# golang
WORKDIR /go-grpc
ENV GO111MODULE on
RUN go get -u github.com/golang/protobuf/protoc-gen-go
./grpc/src/proto/chat.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.chat";
option java_outer_classname = "ChatProto";package chat;
option go_package = "./"; //上記参考サイトのものに追記
service Chat {
rpc Chat (stream ChatRequest) returns (stream ChatReply) {}
}message ChatRequest {
string message = 1;
}message ChatReply {
string message = 1;
}
./grpc/src/server/main.go
package main
import (
"fmt"
"io"
"log"
"net"
"time"pb "grpc-docker/pb/chat"
"github.com/pkg/errors"
"google.golang.org/grpc"
)const port = ":50051"
// ServerBidirectional is server
type ServerBidirectional struct {
pb.UnimplementedChatServer
}func request(stream pb.Chat_ChatServer, message string) error {
reply := fmt.Sprintf("%sを受け取ったよ!ありがとう^^", message)
return stream.Send(&pb.ChatReply{
Message: reply,
})
}// Chat クライアントから受け取った言葉に、言葉を返す
func (s *ServerBidirectional) Chat(stream pb.Chat_ChatServer) error {
for {
in, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
message := in.GetMessage()
fmt.Println("受取:", message)if err := request(stream, message); err != nil {
return err
}
time.Sleep(time.Second * 1)
}
}func set() error {
lis, err := net.Listen("tcp", port)
if err != nil {
return errors.Wrap(err, "ポート失敗")
}
s := grpc.NewServer()
var server ServerBidirectional
pb.RegisterChatServer(s, &server)
if err := s.Serve(lis); err != nil {
return errors.Wrap(err, "サーバ起動失敗")
}
return nil
}func main() {
fmt.Println("起動")
if err := set(); err != nil {
log.Fatalf("%v", err)
}
}
./grpc/src/client/main.go
package main
import (
"context"
"io"
"log"
"time""github.com/pkg/errors"
pb "grpc-docker/pb/chat"
func receive(stream pb.Chat_ChatClient) error {
waitc := make(chan struct{})
go func() {
for {
in, err := stream.Recv()
if err == io.EOF {
close(waitc)
return
}
if err != nil {
log.Fatalf("エラー: %v", err)
}
log.Printf("サーバから:%s", in.Message)// お返し
stream.Send(&pb.ChatRequest{
Message: time.Now().Format("2006-01-02 15:04:05"),
})
}
}()
<-waitc
return nil
}func request(stream pb.Chat_ChatClient) error {
return stream.Send(&pb.ChatRequest{
Message: "こんにちは",
})
}func chat(client pb.ChatClient) error {
stream, err := client.Chat(context.Background())
if err != nil {
return err
}
if err := request(stream); err != nil {
return err
}
if err := receive(stream); err != nil {
return err
}
stream.CloseSend()
return nil
}func exec() error {
address := "localhost:50051"
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
return errors.Wrap(err, "コネクションエラー")
}
defer conn.Close()
client := pb.NewChatClient(conn)
return chat(client)
}func main() {
if err := exec(); err != nil {
log.Println(err)
}
}
ファイル生成
Dockerコンテナを立ち上げる
docker-compose up -d
下記コマンドを実行し、go moduleの初期化を行う
docker-compose exec go-grpc go mod init grpc-docker
すると ./grpc/src/go.mod が生成される
下記コマンドを実行し、gRPCファイルの生成
docker-compose exec go-grpc protoc --proto_path ./proto --go_out=plugins=grpc:./pb/chat chat.proto
すると ./grpc/src/pb/chat/chat.pb.go が生成される
サーバとクライアントの実行
下記コマンドを実行し、gRPCサーバを起動する
docker-compose exec go-grpc go run server/main.go
すると ./grpc/src/go.sum が生成される
下記コマンドを実行し、gRPCクライアントを起動する
docker-compose exec go-grpc go run client/main.go
すると下記スクショのようにサーバ側とクライアント側で出力が表示される。
ようやくgRPC学習のスタートラインに立てた感
次はgRPC-webを動かす方法を調べる
暗中模索
PS
A Tour of Go だけじゃ全然わからんけど、
とほほのGo言語入門 - とほほのWWW入門 を併せて参考にすると理解が捗った。
webRTCを使ってストリーミング鯖
twitchが埋め込みプレーヤー使用制限なんてことがあったので、自前配信サーバーを用立てれないかと思ってwebRTCでP2P動画配信サーバーを作ってみた。
んで、Twitchが埋め込みプレーヤーに対する制限を辞めたようなので、自前配信サーバーを維持することなくなったので、テキトーにコードをgithubに挙げてTURN鯖の設定のメモを残しておく。
動かしてみた感じ、思った以上にみんなTURNサーバを経由せずにブラウザ間でのP2P通信ができているようだった。
ただ、Firefoxだとiframe内でwebRTC p2pがうまくいってないようだった。別ウィンドウだとOK。
webRTCによる動画配信サーバー
socket.io でシグナリングと simple-peer.js でピア接続に使って実装した。
動画配信なので1対多でピアを接続する。
上記ソースの broadcast.js を実行してシグナリングサーバ兼HTTPサーバを立てる。
上記のサーバ用のsystemd を作る
sudo vi /etc/systemd/system/webrtc.service
[Unit]
Description=webrtc service
After=network.target[Service]
Type=simple
ExecStart=/usr/bin/node /var/www/nodejs/broadcast.js
WorkingDirectory=/var/www/nodejs
KillMode=process
Restart=always[Install]
WantedBy=multi-user.target
sudo systemctl restart webrtc
TURN/STUN サーバのインストール
sudo apt install coturn
sudo vi /etc/default/coturn
coturnの設定は下記を参考
TURNサーバがちゃんと動いてるかは下記サイトを使ってテストできる
とりあえず構築メモは以上。
動画配信は現状YouTubeかTwitchの二択みたいな状況だけれども、webRTC標準化によって何かとライブラリが充実したり、TURN/STUNサーバの構築がもっと簡単になるかもしれない。
なんにせよ当初の実験は成功し、今は必要なくなったのでwebRTC配信鯖は閉じけど、また必要になった構築できるようにしておきたい。
今度立てるときは、webRTCのストリームをバケツリレーする感じの仕様に挑戦してみたいね。
現状だと1対多で配信者に対して5人くらい視聴者がつくとカクつくみたいなので、1人あたりMAX3接続、みたいなオープン分散型動画配信システム。
まあ誰かがそのうち実装するだろう
これはいい漫画
自宅動画ストリーミング鯖のススメ(Raspberr Pi + Nginx + libnginx-mod-rtmp)
概要
[ PC ]→rtmp→[ ラズパイ ]→HLS→[ プレーヤー ]
主な手順
- Raspberry Pi セットアップ
- 動画ストリーミング鯖の構築
- Rasppbery Piをインターネットに公開
- ドメイン・SSLを無料で取得、設定
- SSLを無料で取得、設定
1. Raspberry Pi セットアップ
1.1 本体セットアップ
まずは本体を調達
OSをダウンロード
https://www.raspberrypi.org/downloads/raspberry-pi-os/
ダウンロードしたらzipを解凍して2020-月-日-raspbian-ナンタラカンタラ.imgを取り出しておく
SDメモリカードフォーマッター をダウンロード
https://www.sdcard.org/jp/downloads/formatter/
microSDカードをフォーマットしておく
Win32 Disk Imager をダウンロード
https://sourceforge.net/projects/win32diskimager/
2020-月-日-raspbian-ナンタラカンタラ.img を microSDに焼く
1.2 Raspberry Pi のIPアドレスを固定する
Raspberry Pi でnmtuiでIPアドレスを固定してもいいし、ルーター側でMACアドレスからIPアドレスを固定してもいい。
2. 動画ストリーミング鯖の構築
参考にした記事:https://iot-plus.net/make/raspi/raspbian-buster-streaming-server-using-ffmpeg-rtmp-nginx/
2.1 必要なパッケージのインストール
sudo apt upgrade
sudo apt install nginx libnginx-mod-rtmp
2.2 諸々の設定
配信ディレクトリの用意
sudo mkdir -p /var/www/html/live/
cd /var/www/html/live/
sudo ln -s /dev/shm hls
Nginxに配信の設定
rtmpを受け取ってHLSを配信する設定を書く
sudo vi /etc/nginx/conf.d/rtmp
↑/etc/nginx/conf.d/rtmpの中身
rtmp {
server {
listen 1935;
chunk_size 4096;
allow play all;
access_log /var/log/nginx/rtmp_access.log;application live {
live on;
hls on;
record off;
hls_path /var/www/html/live/hls;
hls_fragment 1s;
hls_type live;
}
}
}
Nginxの設定に読みこませる
sudo vi /etc/nginx/nginx.conf
↑/etc/nginx/nginx.conf の末行に下記を書き足す
include /etc/nginx/conf.d/rtmp;
Nginxに設定を反映
sudo systemctl daemon-reload
sudo systemctl restart nginx
2.3 動作の確認
この時点で動画のストリーミングは可能になっている。
OBSの配信設定で、
サービス:カスタム...
サーバー:rtmp://(ラズパイIPアドレス)/live/
ストリームキー:stream
と入力して配信し、VLCプレーヤーを起動して「メディア>ネットワークストリームを開く」で下記URLを指定すると、OBSの配信映像が見れるハズ。
http://(ラズパイIPアドレス)/live/hls/stream.m3u8
3. Rasppbery Piをインターネットに公開
3.1 セキュリティ対策
公開する前に「最低限の」セキュリティ対策をしておく
まずRaspberry Piのデフォルトパスワードを変更する
passwd
そしてルーターのファイアウォールが有効になっていることを確認。
ラズパイにアクセス制限を設定する
sudo vi /etc/hosts.allow
で下記を末尾に書き足す。下記例は自分のPCのIPアドレスが「192.168.1.2」の場合
ALL:192.168.1.
そして
sudo vi /etc/hosts.deny
で下記を末尾に書き足す
ALL:ALL
上記の設定ができたら、ルーター側でポートフォワーディングの設定する
固定したラズパイのアドレスに対してHTTP「80」とHTTPS「443」のフォワーディングを設定する
ポートフォワーディングの設定方法についてはルーターによって違うので割愛
設定が適切に出来ていたら、外の回線(例えばiPhoneとかで自宅Wi-Fiに繋いでない状態で)自宅のグローバルIPにアクセスしたらNginxの初期ページが表示されるハズ
グローバルIPは下記サイトとかで確認する
https://www.cman.jp/network/support/go_access.cgi
4. ドメインで取得、設定
この段階で外部に配信はできるけども、家庭用のネット回線のグローバルIPは変動するので、ドメイン(ホニャラリ.com)を取得して、常に同じURLでアクセスできるようにする
通常ドメインの取得には維持費がかかるが、無料のダイナミックDNSを利用する方法がある
ここではMyDNSでの設定を紹介する
4.1 MyDNSでアカウント登録
MyDNSに新規登録はここ(わかりづらい)
ここに開通用のメールアドレス他、個人情報とか入力する
登録ができると、メールアドレス宛にマスターIDとパスワードが記載されたメールが届くハズ
そのログイン情報をつかってMyDNSにログインする。
4.2 ドメインの取得
MyDNSにログインできたら「DOMAIN INFO」からお好みのドメインを設定する。
この辺読むのがいいと思う
https://nw.myds.me/synology/setup-domain/
4.3 ドメインの自動更新
ログイン情報を元に、定期的にMyDNSに現在のグローバルIPを通知するスクリプトを作成する
vi /home/pi/noticeIp.sh
中身はこんな感じ
#!/bin/bash
wget -O - 'http://mydns000000:xxxxxxxxx@ipv4.mydns.jp/login.html'
mydns000000がマスターID
xxxxxxxxxがパスワードになる
スクリプトが作成できたら、それに実行権限を与える
sudo chmod 755 /home/pi/noticeIp.sh
試しに実行してみる
/home/pi/noticeIp.sh
なんか色々文字列が返ってきて「Login and IP address notify OK.」って文字がどこかにあればOK
ダメならなんかダメってメッセージが返ってくる
ちゃんと認証・グローバルIP通知ができたら、cronで定期実行してやるようにする
crontab -e
エディタが立ち上がるので
30 * * * * /pi/home/noticeIp.sh
を末尾に加える。
おそらくこの時点で、先に設定したドメインにアクセスしたら自分のグローバルIPに転送されるようになってるはず。
ちなみに外部ネットワークから(スマホでWi-Fiに繋がずに4G回線とかで)ドメインに接続したらRasppbery PiのNginx初期ページが表示されるだろうけども、自宅PCからドメインに接続してもルーターの設定画面を開くことになるかもしれない。
それはDNSの設定で色々ややこしいので、一番簡単な「自宅PCのhostsにMyDNSで取得したドメインに、Rapsberry PiのローカルIPを設定する」をオススメする。
5. SSLを無料で取得、設定
通常SSLは維持費が掛かるが、MyDNSと同じ用に定期的に通知することで無料で取得できるサービスがある。
それが「Let’s Encrypt」https://letsencrypt.org/ja/
5.1 certbotのインストール
下記三つのコマンドを実行する
cd /usr/local/
sudo git clone https://github.com/certbot/certbot
sudo /usr/local/certbot/certbot-auto
5.2 SSL証明書の取得
ここではMyDNSで取得したドメインを sample.mydns.jp とし、連絡先メールアドレスを sample@mail.com とする。適時買い替えて下記コマンドを実行する。
/usr/local/certbot/certbot-auto certonly --webroot -w /var/www/html/ -d sample.mydns.jp -m sample@mail.com
ちゃんとポートフォワーディングとMyDNSの設定とNginxの設定が適切であれば
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/sample.mydns.jp/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/sample.mydns.jp/privkey.pem
といったメッセージが表示されてSSL証明書が保存されている。
あとSSL証明書も自動更新するように設定する
sudo crontab -u root -e
して下記行を末尾に加える
00 02 01 * * /usr/local/certbot/certbot-auto renew --force-renew --webroot-path /var/www/html/ --deploy-hook "systemctl reload nginx"
5.3 SSL証明書の反映
取得したSSLはNginxに反映する必要がある。
sudo vi /etc/nginx/nginx.conf
を開くと色々あるけど34行目あたりに
##
# SSL Settings
##ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;##
# Logging Settings
##
といった記述があるはず。
このssl_prefer_server_ciphers on;の下あたりに設定を追記する。
上記がこんな感じになるはず
##
# SSL Settings
##ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
server {root /var/www/html;
listen 443 ssl;
server_name sample.mydns.jp;
ssl_certificate /etc/letsencrypt/live/sample.mydns.jp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sample.mydns.jp/privkey.pem;
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Methods 'GET';
add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type';
add_header Access-Control-Max-Age 3600;}
##
# Logging Settings
##
上記を入力したらNginxを再起動して反映させる
sudo systemctl restart nginx
これでhttps://sample.mydns.jp/live/hls/stream.m3u8 を外部ネットワークからiPhoneやVLCプレーヤーで開けたら完了。
owari
さいごにオススメ漫画
幼少期編は正直顔のバランスに違和感感じる濃ゆいだけの漫画だけど、読んでたらマジで面白いからぜひポチってほしい
RubyでTwitchAPIをOAuth認証して叩くスクリプト
最近TwitchAPIがOAth認証してないと401を返すようになった
どうやら2020/5/12頃にアプデがあったようだ
https://discuss.dev.twitch.tv/t/requiring-oauth-for-helix-twitch-api-endpoints/23916
https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#oauth-client-credentials-flow
色々調べてRubyでクライエントIDとクライエントシークレット(ダッシュボードではクライアントの秘密という)でOAuth認証する「OAuth client credentials flow」に従って回収した。
もしはじめてAPIを叩く実装するなら、あらかじめhttps://dev.twitch.tv/でアプリケーション登録してクライエントIDとクライエントシークレットを取得してね
require 'net/http'
require 'json'
require 'uri'
// https://dev.twitch.tv/console/apps で取得する「クライアントID」と「クライアントの秘密」
client_id = "xxxxxxxxxxclient_idxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxclient_secretxxxxxxxxxxxxx"
// 配信を調べたいTwitchのユーザー名
twitch_id = "ink_kasekai"
// アクセストークンの取得
uri = URI.parse("https://id.twitch.tv/oauth2/token?client_id=#{client_id}&client_secret=#{client_secret}&grant_type=client_credentials")
response = Net::HTTP.post_form(uri ,{})
p response.code # status code
res_json = JSON.parse(response.body)// アクセストークンを取得できた
access_token = res_json['access_token']
// アクセストークンを使ってAPI叩いてTwitchユーザー名からTwitchユーザーIDを取得
url = "https://api.twitch.tv/helix/users?login=#{twitch_id}"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json", "Client-ID" => client_id, "Authorization" => "Bearer #{access_token}"}
response = http.get(uri, headers)
res_json = JSON.parse(response.body)//ユーザーID取得できた
user_id = res_json["data"][0]["id"]
// アクセストークンを使ってAPI叩いてTwitchユーザーIDから配信情報を取得
url = "https://api.twitch.tv/helix/streams?user_id=#{user_id}"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json", "Client-ID" => client_id, "Authorization" => "Bearer #{access_token}" }
response = http.get(uri, headers)
res_json = JSON.parse(response.body)// 配信所法取得できた
p res_json['data']
配信してたらデータに中身ある。中身が空なら配信してない
だいたいこんなかんじ
エミリコはかわいいわね
RubyからストリーミングサービスAPIで指定ユーザーが配信しているか確認(Twitch Mixer YouTubeLive)
配信サービスのユーザー名から現在配信しているか否かを判定するためのRubyコード
が前提
Twitch
ここのGetting a client IDの(register your application on the Twitch developer portal.)からClientID("twichclientidxxxxxxxxxxxxxxxxx")を取得しておく。
streamer_idはTwitterのユーザー名
def get_streaming_status( streamer_id )
response = twitch_client( "https://api.twitch.tv/helix/users?login=#{streamer_id}" )
res_json = JSON.parse(response.body)
if res_json["data"].present? then
id = res_json["data"][0]["id"]
response = twitch_client( "https://api.twitch.tv/helix/streams?user_id=#{id}" )
res_json = JSON.parse(response.body)
return res_json
else
return nil
end
end
def twitch_client( url )
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json", "Client-ID" => "twichclientidxxxxxxxxxxxxxxxxx" }
response = http.get(uri, headers)
return response
end
Mixer
ここからClientID("mixerclientidxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")を取得する。
def get_streaming_status_mixer( streamer_id )
response = client_mixer( "https://mixer.com/api/v1/channels/#{streamer_id}?fields=online" )
if response.code.to_i != 200 then
return true
end
res_json = JSON.parse(response.body)
if res_json["online"].present? && res_json["online"] == true then
return true
else
return nil
end
enddef client_mixer(url)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json", "Client-ID" => "mixerclientidxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }
response = http.get(uri, headers)
return response
end
YouTube Live
ここからYouTubeDataAPIキー(YouTubeDataAPIkeyxxxxxxxxxxxxxxxxxxx)を取得しておく。
※YouTubeのAPIキーの1日あたりの制限はしぶっちいので5分に1回とかだと簡単に上限に達するので注意
YouTube LiveはビデオIDかチャンネルIDかで方法が違う
def get_streaming_status_youtube_videoID( video_id )
url = "https://www.googleapis.com/youtube/v3/videos?id=#{video_id}&key=YouTubeDataAPIkeyxxxxxxxxxxxxxxxxxxx&part=snippet"
return get_streaming_status_youtube( url );
end
def get_streaming_status_youtube_channelID( channel_id )
url = "https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&eventType=live&channelId=#{channel_id }&key=YouTubeDataAPIkeyxxxxxxxxxxxxxxxxxxx"
return get_streaming_status_youtube( url );
enddef get_streaming_status_youtube( url )
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"
headers = { "Content-Type" => "application/json" }
response = http.get(uri, headers)
if response.code.to_i != 200 then
return true
end
res_json = JSON.parse(response.body)
if res_json.blank? || res_json["items"].blank? || res_json["items"][0]["snippet"]["liveBroadcastContent"] == "none" then
return false
else
return true
end
end
以上
全然関係ないけどオススメの漫画はる
とてもオススメしたい
上記スクリプトは配信チャットで実装するのに必要でした
https://ikasekai.com/highchat/
Laravel Echo (Websocket ブロードキャスト)を試す
最近PHPのフレームワークを触る機会が増えて、RailsのActionCableみたいなことがLaravelのEcho(ブロードキャスト 6.x Laravel)で実現できるらしいと興味を持ったので試してみた。
だいたい下記記事の通りだけど、一部記載の通りでは動作しなかったところもあるので捕捉的にで実現できるらしいと興味を持ったので試してみた。
だいたい下記記事の通りだけど、一部記載の通りでは動作しなかったり躓いたところもあるので捕捉として、Laravel初心者なので環境の構築からメモを残す。お試しのVbox上構築なので、セキュリティ対策とかそんな吟味してないので気を付けて!
長いのでまとめると
- チャンネル購読するにはクライアント側でチャンネル名にRedisのprefix(laravel_database_)を足す必要があった。
- ポート開放(firewall-cmd)忘れずに。
- laravel-echo-server start でエラーでたら下記コマンドで直った。
sudo npm install n -g
sudo n latest
環境
- CentOS 7
- VirtualBox ネットワークはブリッジアダプタ(ipは 192.168.0.100 とする)
- PHP 7.3
- Laravel Framework 6.6.0
- Apache/2.4.6
- mariadb-server
- Redis
「larapro」が今回のテスト用のlaravelプロジェクト名です
ユーザー名は「centuser」ということにします。
構築
sudo yum install epel-release
sudo rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
sudo yum -y install --enablerepo=remi,remi-php73 php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt
sudo yum -y install --enablerepo=remi,remi-php73 php-opcache php-mysqlnd
sudo yum -y install --enablerepo=remi,remi-php73 composer
sudo yum -y install --enablerepo=remi,remi-php73 php-pecl-redis
DB周り
sudo yum install mariadb mariadb-server mariadb-client
sudo vi /etc/my.cnf
[client]
default-character-set=utf8mb4[mysql]
default-character-set=utf8mb4[mysqldump]
default-character-set=utf8mb4[mysqld]
character-set-server=utf8mb4
sudo systemctl start mariadb
sudo systemctl enable mariadb
sudo mysql_secure_installation
mysql -u root -p
文字コードの確認 UTF8mb4になってればOK
MariaDB [(none)]> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
- | character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
適当にデータベースを用意する
MariaDB [(none)]> CREATE DATABASE test_laravel;
Apache httpd周り
sudo mkdir /var/www/project
sudo chmod 2775 /var/www/project/
sudo chown apache:apache /var/www/project/
sudo usermod -aG apache centuser
sudo vi /etc/httpd/conf/httpd.conf
Vbox上でIPアクセスするのでバーチャルホストではなくDocuRoot直接設定しちゃう
DocumentRoot "/var/www/project/larapro/public"
<Directory "/var/www">
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/project">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
sudo systemctl restart httpd
sudo systemctl enable httpd
Redis
sudo yum install redis
sudo systemctl enable redis
sudo systemctl start redis
redis-cli
Firewall ポート開放
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-port=6001/tcp --permanent
sudo firewall-cmd --reload
Laravel構築
cd /var/www/project/
composer create-project --prefer-dist laravel/laravel larapro
cd larapro
npm install --save laravel-echo socket.io-client
composer require predis/predis
npm install -g laravel-echo-server
laravel-echo-server init
こんな感じで対話形式でLaravel Echoの設定する
192.168.0.100 のところは各々の環境のアドレスを設定してください
? Do you want to run this server in development mode? Yes
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. http://192.168.0.100
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? Yes
? Do you want to setup cross domain access to the API? Yes
? Specify the URI that may access the API: http://192.168.0.100:80
? Enter the HTTP methods that are allowed for CORS: GET, POST
? Enter the HTTP headers that are allowed for CORS: Origin, Content-Type, X-Auth-Token, X-Requested-With, Accept, Authorizat
ion, X-CSRF-TOKEN, X-Socket-Id
? What do you want this config to be saved as? laravel-echo-server.json
appId: xxxxxxxxxxxxxxxx
key: 01010101010101010101010101010101
Configuration file saved. Run laravel-echo-server start to run server.
sudo laravel-echo-server start
※もし
Starting server in DEV mode...
/usr/lib/node_modules/laravel-echo-server/node_modules/ws/lib/websocket.js:347
...options
^^^
というエラーがでたら
sudo npm install n -g
sudo n latest
を実行しよう
ここから先はだいたい参考記事(https://qiita.com/zaburo/items/34289d4573f39113b25a)と同じ
ディレクトリは引き続きプロジェクトルート(/var/www/project/larapro)にて
vi config/app.php
vi .env
php artisan make:event PublicEvent
vi ./app/Events/PublicEvent.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;class PublicEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('hoge-channel');
// return new PrivateChannel('channel-name');
}
public function broadcastWith()
{
return [
'message' => 'PUBLIC',
];
}
}
vi ./routes/web.php
ここでは「/fire」にアクセスしたらEvent発火させることにした
Route::get('/', function () {
return view('welcome');
});Route::get('/fire', function(){
broadcast(new \App\Events\PublicEvent);
return 'public';
});
vi ./resources/js/bootstrap.js
ファイル末尾に下記を挿入
import Echo from 'laravel-echo';
window.io = require('socket.io-client');//接続情報
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});//購読するチャネルの設定
window.Echo.channel('laravel_database_hoge-channel')
.listen('PublicEvent', (e) => {
console.log(e);
});
※余談ハマった点
window.Echo.channel('laravel_database_hoge-channel')
購読チャンネル名は「hoge-channel」だが、それに加えて「laravel_database」をprefixとして頭に付け加えなければならなかった。
prefixがどこで設定されているかというと「./config/database.php」のこのあたり
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
npm run dev
vi ./resources/views/welcome.blade.php
<head>内に挿入
<body>タグ最後に挿入
<script src="{{ asset('js/app.js')}}"></script>
あとは参考記事(https://qiita.com/zaburo/items/34289d4573f39113b25a)と同じように、「http://192.168.0.100/」でコンソールを開いておいて「http://192.168.0.100/fire」を開いたらコンソールにPUBLICと表示されたら成功
おしまい
プライベートチャンネルは必要になったらまた試すかも
でもあとは参考記事と同じで大丈夫だと思う
重ねて感謝