2018年6月8日金曜日

VS2017でDXライブラリ用テンプレートを作ってみた。

DXライブラリでゲームを作るとき、毎度プロジェクトの設定をしなければ
いけないのが思いのほかめんどくさく感じていたので、
このたびプロジェクトテンプレートを作成してみました。

以下がテンプレートのファイルです。(VisualStudio2017で作成しています。)
DXLib.zip

インストール手順:
・上記ファイルをそのままドキュメントフォルダの
 ”Visual Studio 2017\Templates\ProjectTemplates\Visual C++ プロジェクト”
 配下に置く。
・VisualStudio開発者コマンドプロンプトを「管理者として実行」で開いて
 ”devenv /installvstemplates"
 を実行する。
・VisualStudioを起動する。
プロジェクトの新規作成ダイアログで上記画像のようになっていれば
インストール完了です。

※なお、DXライブラリのフォルダはC:\直下に置いてください。
(というか公式マニュアルどおりにセットアップすれば問題ないです。)

2017年10月23日月曜日

Chinachuの録画ファイルを自動削除

Chinachu自体にも自動的にファイルを削除する機能はありますが、
あくまでも容量が足りなくなったときのみの機能なので、
1週間以前の録画ファイルを削除するスクリプトを作成してみました。

#!/bin/bash

day_count=7
tsdir="/mnt/storage/share/tv/"
logdir="/opt/chinachu/log/tsdel/"

nowstr=`date +%y%m%d%H%M%S`
logfile=${logdir}${nowstr}.log
datestr=`date --date "${day_count} days ago" +%y%m%d`

echo "------- TS File Delete Start -------" >> ${logfile}
count=0
for filepath in ${tsdir}*; do
  filename=`basename ${filepath}`
  filename=${filename:1:6}
  if [ ${filename} -lt ${datestr} ] ; then
    rm -fv "${filepath}" >> ${logfile} 2>&1
    let count++
  fi
done

echo "------- ${count} Files Deleted. -------" >> ${logfile}

if [ $count -gt 0 ] ; then
  echo "------- Chinachu Cleanup Start -------" >> ${logfile}
  expect -c "
    set timeout 5
    spawn /opt/chinachu/chinachu cleanup
    expect \"\[Y/n\]?\ \"
    send \"Y\n\"
    expect \"$\"
    exit 0
  " >> ${logfile} 2>&1
  echo "------- Chinachu Cleanup End. -------" >> ${logfile}
fi

echo "------- TS File Delete End. -------" >> ${logfile}
以上、コイツをcronにぶち込んで運用しています。

2017年5月5日金曜日

Mastodonのアップデート

マストドンは頻繁に更新されています。
せっかく自分専用インスタンスを立てたのだから、最新版を
追いかけたくなるのが人情ってもんですw
ということで、アップデートの手順です。
su - mastodon

cd live

git fetch

git checkout $(git tag | sed -e "/rc/d" | tail -n 1)

bundle install

yarn install

RAILS_ENV=production bundle exec rails db:migrate

RAILS_ENV=production bundle exec rails assets:precompile

sudo pm2 restart mastodon-*.service
あとは正常に動作しているか確認すれば終了です!

Mastodonに管理アカウントを設定する。

マストドンのインスタンスを立ち上げてみてはものの、
このままの状態では誰も管理アカウントが居ない状態になっています。
なので自分のアカウントを追加した状態で、
su - mastodon

cd live

RAILS_ENV=production bundle exec rails mastodon:make_admin USERNAME=#自分#
を実行。
めでたく管理者アカウントに昇格できました!

Mastodonのサーバ通信切れを予防する

無事に自分用マストドンインスタンスを開設できたわけですが、
一つ重要な設定を忘れていることに気がつきました。
つーかちゃんと公式マニュアル見ろって話ですw

で、参考にしたサイトはこちら。
Qiita:Mastodonのサーバ間通信が切れた場合のリカバリ

crontab -eで編集します。
crontab -e
通常であれば、
cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:daily
をcronに追加すればいいようなのですが、
実はこれ、リソースの少ないサーバでは落ちるという事例があるようで、
今の契約はVPSの最安プラン(512MBプラン)という貧弱なものなので、
安全策でこのような設定にしてみました。
MAILTO=root
10 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:feeds:clear'
15 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:media:clear'
20 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:users:clear'
25 4,16 * * * /bin/bash -l -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rake mastodon:push:refresh'
とりあえずコレで一安心ですw

Mastodonインスタンスを立ててみる

今流行のマストドンインスタンスを立ててみました。
Dockerを使えば簡単に導入できるようですが、今回はあえて手動でやってみました。

下記手順の前提条件:
・さくらのVPS(標準OS:Ubuntu16.04)
・ドメイン取得済み[mstdn.imoimo.xyz](今回はお名前.comを利用させて頂きました。)
・諦めない心


参考サイト:
公式マニュアル
Qiita:さくらのVPSで自分の Mastodon サーバを最速でつくる方法
稲葉サーバーデザイン:Let’s EncryptによるSSLサーバー証明書の自動更新設定

443ポート、動作確認用ポートを開放するために、iptablesの設定を編集
sudo vi /etc/iptables/iptables.rules
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT

#さくらのVPS標準OSはデフォルトで22番ポート(ssh)だけが開放されている。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

#httpsポートを追加。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT

#Mastodon動作確認用でこちらも。後で削除する。
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT

-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

iptablesの設定内容を反映
sudo iptables-restore < /etc/iptables/iptables.rules

mastodonユーザを作成し、mastodonユーザでログイン
sudo adduser -ingroup sudo mastodon

su - mastodon

依存関係のあるパッケージなどをインストール
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file git curl

curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -

sudo apt-get install nodejs

sudo npm install -g yarn

Redisのインストール
sudo apt-get install redis-server redis-tools

Postgresのインストール
sudo apt-get install postgresql postgresql-contrib

sudo postgresql-setup initdb

sudo systemctl start postgresql

sudo systemctl enable postgresql

Postgresにmastodonユーザを作成
sudo su - postgres

psql

CREATE USER mastodon CREATEDB;

\q

Postgresのおまじない(ローカルユーザからはパスワード要求しない設定っぽい)
sudo sed -i '/^local.*postgres.*peer$/a host    all     all     127.0.0.1/32    ident' /etc/postgresql/9.?/main/pg_hba.conf

identのインストール
sudo apt-get install pidentd

sudo systemctl enable pidentd

sudo systemctl start pidentd

sudo systemctl restart postgresql

Rbenvのインストール
git clone https://github.com/rbenv/rbenv.git ~/.rbenv

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

~/.rbenv/bin/rbenv init

source ~/.bash_profile

rbenvが無事インストールされているか確認
exit

su - mastodon

type rbenv

rbenv-build のインストール
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build

rubyのインストール
rbenv install 2.4.1

rbenv rehash

rbenv global 2.4.1

rubyが正常にインストールされたか確認
ruby -v

Mastodon本体を取得
mastodonユーザのHomeにliveディレクトリを作成し、そこに格納。
cd ~

git clone https://github.com/tootsuite/mastodon.git live

cd live

git checkout $(git tag | tail -n 1)

依存パッケージ(RubyGems)のインストール
gem install bundler

bundle install --deployment --without development test

yarn install

rakeのシークレットキーを生成(3回実行し、3個生成しておく)
rake secret

.env.productionの編集
cp .env.production.sample .env.production

vi .env.production
#RdisとPostgresは同一サーバに構築したので、そのように設定。
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
DB_HOST=127.0.0.1
DB_USER=mastodon
DB_NAME=mastodon
DB_PASS=
DB_PORT=5432

#Mastodonで使うドメイン名を設定
LOCAL_DOMAIN=mstdn.imoimo.xyz
#動作確認のため、falseに設定しておく(あとでtrueに戻す)
LOCAL_HTTPS=false

#それぞれrake secretで作成したシークレットキーを設定する。
PAPERCLIP_SECRET=#シークレットキー#
SECRET_KEY_BASE=#シークレットキー#
OTP_SECRET=#シークレットキー#

#とりあえずGmailアカウントを作ってそれを使うことにした。
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
SMTP_LOGIN=mstdn.imoimo@gmail.com
SMTP_PASSWORD=#GMailのログインパスワード#
SMTP_FROM_ADDRESS=mstdn.imoimo@gmail.com
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_DOMAIN=gmail.com

Mastodonのビルド
RAILS_ENV=production bundle exec rails db:setup

RAILS_ENV=production bundle exec rails assets:precompile

systemdの設定(自動起動)
sudo vi /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
sudo vi /etc/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
sudo vi /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target

Mastodonサービスを起動
sudo systemctl enable /etc/systemd/system/mastodon-*.service

sudo systemctl start mastodon-web.service mastodon-sidekiq.service mastodon-streaming.service

とりあえず動作確認
これでマストドンのAboutページが出れば成功!
http://<サーバのIPアドレス>:3000

Let's Encrypt(certbot)のインストール
cd /usr/local

sudo git clone https://github.com/certbot/certbot

certbotが正常にインストールされたことを確認
certbotのヘルプが表示されればOK。
cd /user/local/certbot

sudo ./certbot-auto --help

証明書を取得する
certbot-auto certonly --standalone -d mstdn.imoimo.xyz -m mstdn.imoimo@gmail.com --agree-tos -n

証明書を自動更新するためのスクリプトを作成する
sudo vi /usr/local/certbot/certbot.sh
#!/bin/sh
#
LOGFILE=/var/log/update_sslcert.log
COMMAND=/usr/local/certbot/certbot-auto
WEBSERVER_STOP_COMMAND="systemctl stop nginx"
WEBSERVER_START_COMMAND="systemctl start nginx"

MAILTO=root

echo "===== Update SSL Cert =====" >> ${LOGFILE}
echo "`date` Update SSL Cert start" >> ${LOGFILE}

${COMMAND} renew \
  --pre-hook "$WEBSERVER_STOP_COMMAND" \
  --post-hook "$WEBSERVER_START_COMMAND" \
  --non-interactive >> ${LOGFILE}
STATUS=$?

if [ "$STATUS" != 0 ]; then
    echo "Update SSL Cert failed" >> ${LOGFILE}
    echo "Update SSL Cert failed" |\
    mail -s "Update SSL Cert in `hostname`" ${MAILTO}
fi

echo "`date` Update SSL Cert end" >> ${LOGFILE}

# EOF

先ほど作成したスクリプトをcronに追加する
sudo crontab -e
50 4 * * 4 /usr/local/certbot/certbot.sh > /dev/null

Nginx(httpsプロキシとして使用)のインストール
sudo apt-get install nginx

Nginxの設定
公式ドキュメントのサンプルをそのまま流用。
sudo vi /etc/nginx/conf.d/mastodon_proxy.conf
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  listen [::]:80;
  server_name mstdn.imoimo.xyz;
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { allow all; }
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name mstdn.imoimo.xyz;

  ssl_protocols TLSv1.2;
  ssl_ciphers EECDH+AESGCM:EECDH+AES;
  ssl_ecdh_curve prime256v1;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  ssl_certificate     /etc/letsencrypt/live/mstdn.imoimo.xyz/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mstdn.imoimo.xyz/privkey.pem;
  ssl_dhparam         /etc/ssl/certs/dhparam.pem;

  keepalive_timeout    70;
  sendfile             on;
  client_max_body_size 0;

  root /home/mastodon/live/public;

  gzip on;
  gzip_disable "msie6";
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 6;
  gzip_buffers 16 8k;
  gzip_http_version 1.1;
  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

  add_header Strict-Transport-Security "max-age=31536000";

  location / {
    try_files $uri @proxy;
  }

  location /assets {
    add_header Cache-Control "public, max-age=31536000, immutable";
  }

  location @proxy {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://127.0.0.1:3000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  location /api/v1/streaming {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Proxy "";

    proxy_pass http://localhost:4000;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    tcp_nodelay on;
  }

  error_page 500 501 502 503 504 /500.html;
}

.env.productionのLOCAL_HTTPSをtrueに変更する
vi ~/live/.env.production

iptablesで開けていた3000番ポートを閉じて、設定を反映
sudo vi /etc/iptables/iptables.rules

sudo iptables-restore < /etc/iptables/iptables.rules

MastodonとNginxの再起動
sudo systemctl restart mastodon-sidekiq.service

sudo systemctl restart mastodon-web

sudo systemctl restart nginx

最終動作確認
https://mstdn.imoimo.xyz
コレで無事マストドンが表示されれば成功!
ハマり所はLet's Encryptとポート開放の辺りでしょうか・・・
ぶっちゃけ結構大変でした・・・w

2017年2月20日月曜日

Twitterの自動返信BOTをPHPで実装

// TwitterOAuthライブラリを使用
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

// ログファイル
define("LOG_FILE","koimoimo.log");
// 最新ツイートIDを保存するファイル
define("LATEST_FILE","latest.txt");

//TwitterのOAuth用パラメータ
define("C_KEY","--Consumer Key--");
define("C_SEC","--Consumer Secret--");
define("A_TOK","--Access Token--");
define("A_SEC","--Access Token Secret--");

// 自分自身のTwitter ID(@なしで指定)
define("MYNAME","--My Twitter ID--");
// 非公式RT用返信ヘッダ
define("MENTION_HEAD","ホアーッ RT @");
// マッチング文字列を配列に格納
$key_arr = [
"ブチッ",
"ブチッ",
"ぶちっ",
"シャコン",
"ブチっ",
"ぶちぶち",
"ブチブチ",
"ブチブチ"
];

// OAuthでTwitterに接続
$connection = new TwitterOAuth(C_KEY,C_SEC,A_TOK,A_SEC);
// 前回の最新ツイートIDを取得
$latest = load_file(dirname(__FILE__)."/".LATEST_FILE);
// ホームタイムラインからツイートを取得
$tl = $connection->get("statuses/home_timeline", ["count" => 200]);
// 今回の最新ツイートIDを保存しておく
save_file(dirname(__FILE__)."/".LATEST_FILE,$tl[0]->id_str);
// ツイートをスキャンし、マッチング文字列にヒットしたら非公式RTする
foreach($tl as $t){
    // 送信者が自分自身以外のツイートと、前回の最新より新しいツイートに絞る
    if($t->user->screen_name != MYNAME && $t->id_str > $latest){
        // ツイートをマッチング文字列配列でスキャンし、ヒット数を返す。
        $sc = get_key_score($t->text,$key_arr);
        // ヒット数が1以上で、かつツイート中に自身のIDが含まれるものに絞る
        if($sc > 0 && mb_strstr($t->text,"@".MYNAME) != NULL){
            // 多重メンション防止
            if(mb_strstr($t->text,MENTION_HEAD) == NULL){
                // 返信を投稿する
                send_mention($connection,$t->user->screen_name,$t->text);
            }
        }
    }
}

// ファイルを開き、内容を文字列変数に格納する
function load_file($filename)
{
    $fp = fopen($filename,"r");
    $buf = fgets($fp);
    fclose($fp);
    return $buf;
}

// 文字列変数の内容をファイルに書き込む
function save_file($filename,$buf)
{
    $fp = fopen($filename,"w");
    fwrite($fp,$buf);
    fclose($fp);
}

// 文字列変数の内容をファイルに追記する
function append_log_file($filename,$buf)
{
    $fp = fopen($filename,"a");
    fwrite($fp,$buf."\n");
    fclose($fp);
}

// 文字列からマッチング文字列配列のヒット数を返す
function get_key_score($txt,$key)
{
    $s = 0;
    foreach($key as $k){
        if(mb_strstr($txt,$k) != NULL) $s++;
    }
    return $s;
}

// 非公式RT形式でツイートし、内容をログに残す
function send_mention($con,$usr,$txt)
{
    $m = MENTION_HEAD.$usr.": ".$txt;
    if(mb_strlen($m) > 140) $m = mb_strimwidth($m,0,140,"...");
    $r = $con->post("statuses/update", ["status" => $m]);
    append_log_file(dirname(__FILE__)."/".LOG_FILE,date("Ymd_His").":".$m);
    return $r;
}