著者名が「magicien
21〜30件目 / 212件
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 次へ

 GitHubから取得したファイルをindexedDBに保存する / magicien 

ブラウザ(JavaScript)からGitHubのリポジトリのアーカイブを取得・展開するの続き。
展開したファイルをIndexedDBに保存する。


DBのオープンやデータの更新を要求すると、戻り値として IDBRequest のオブジェクトが返ってくる。このオブジェクトの onsuccess と onerror に関数を設定すると、処理が終わった時に呼び出される。ソースはこんな感じ。例によって検証していないので、typoとかバグとかあるかも。

リクエストを発行してからでないとコールバック関数が設定できないのは設計がおかしいんじゃなかろうか。
とりあえず、getResult関数でonsuccess、onerrorをPromiseでラップしておく。transactionの場合は、イベント名がちょっと違って、oncomplete、onerror、onabort になる。ディスクの空き容量が足りないと、QuotaExceededError が起きて onabort が呼び出される。手元のMacBook Airだとこのエラーが頻繁に起きる。
IndexedDBで使える容量はブラウザや状況(ディスクの空き容量)によって変わるようで、ひどい時はChromeで容量上限が10KBだった。おまえ、キャッシュとかswapとかで軽く数GB食いつぶすくせにIndexedDBには厳しすぎない?まぁ無いものは無いのでエラーを出して終了するしかない。Chromeを終了してディスクを解放してから再起動すると上限が1GBに増えていたりする。

2017/10/08(Sun) 07:46:30

 ブラウザ(JavaScript)からGitHubのリポジトリのアーカイブを取得・展開する / magicien 

需要がありそうで全く無い、ブラウザのJavaScriptで、GitHubからリポジトリをzipで落とす方法。

GitHubのAPIドキュメントによると、GET /repos/:owner/:repo/:archive_format/:ref でアーカイブがダウンロードできるらしい。
archive_formatは、zipball か tarball の二択。ref はブランチ名とかタグ名とか。リクエストを送ると、302のリダイレクトでダウンロードURLを教えてくれる(https://codeload.github.com/... とか)。

問題は、codeload.github.comがクロスドメインを許可していないこと。JavaScriptでダウンロードしようとすると、ブラウザ側で自主規制がかかって失敗する。仕方が無いので、サーバを経由してダウンロードさせることにする。サーバがGitHub Appのアクセストークンを持っているなら、プライベートなリポジトリもダウンロードできる(5分間だけ有効なダウンロードURLを教えてもらえる)ので、これが正しい方法なのだろう。

ソースコードはこんな感じ。実際に使っているものを抜粋・編集したものだけれど、未検証なので動かないかもしれない。
ここぞとばかりにasync/awaitを使ってみたが、.then.then.thenでも良いと思う。

続き:GitHubから取得したファイルをindexedDBに保存する

2017/10/06(Fri) 06:34:12

 Swift4.0でCodableなクラスを継承した場合の挙動 / magicien 

なんか想定と違ったので色々確認することにした。

結論から言うと、継承したクラスでは、init(from decoder: Decoder)を自分で実装しないとだめ。
継承元のクラスはinitを省略可。省略した場合でも、サブクラスからsuper.init(from:)を呼ぶとちゃんとパースしてくれる。

2017/10/03(Tue) 09:58:24

 ARKitの動画再アップ / magicien 

以前ニコニコ動画にアップしていた(その後削除した)ARKitの動画を再アップしました。


もはや今更な感じがするけれども。
Xcodeをバージョンアップしたら、UIColorの仕様がちょっと変わっていた。というかNSColorとほぼ同じになっていた。これでOSによる分岐が無くせるかも。むしろ今まで微妙にインタフェースが違ったのは嫌がらせか何かだったのか。

2017/09/27(Wed) 14:00:29

 Heroku/Node.js/ExpressでGitHub AppsのInstallation認証 / magicien 

GitHub Appsとしてリポジトリの操作が必要な場合は、Installation認証が必要。
ユーザは無関係の認証なので、サーバ・GitHub間だけで完結する。

ソースはこんな感じ。
Installation IDは、ユーザ認証のときに取得する必要がある。
ユーザとは無関係に操作できてしまうので、操作を要求しているユーザが対象のInstallationのアクセス権を持っているか確認が必要。

2017/09/15(Fri) 04:05:03

 新iPhone! / magicien 

既に色々と情報がリークしていましたが、ようやく新iPhoneが発表されましたね。

iPhone9が欠番になっちゃいましたが、8sの代わりに9が出たりするのかなぁ。Xも出ちゃったので以降のネーミングはmacOSみたいな感じになりそうですね。

個人的にはAnimojiが一番気になりました。顔認証技術をそうやって使うのかと。
そのうちMacBookにも同じ機能が付くのかなぁ。MMDの表情モーションを自分で演じて作るというのも面白いかもですね。
Dot Projectorというパーツが増えていたので、Kinectと同じようなことをしているんでしょう。Microsoftと何らかのやり取りがあったんでしょうか。ここら辺の技術はどこが持っているのか。
(追記:2013年にAppleがイスラエルのPrimeSenseという会社を買収していたようですね。Kinectのセンサーを作っていた会社らしいです。4年前からFaceIDの開発が進められていたってことですかね。対してKinectは生産終了...うーむ。iPhoneのDot Projectorで姿勢検知までできるようになると良いですね。)

もう一つ気になったのは、Apple TVとiPhoneのHDR対応。ディスプレイ側がHDRに対応するとなると、シェーダはどうやって書けば良いんでしょう。HDR対応有無でシェーダ書き分けるのとか面倒そう...

そういえば、Touch IDで他人がロックを解除できる確率は1/50,000とか言っていたけれど、結構確率高くないですか。まぁiPhoneに限らず、指紋認証機能を使っていると、自分の指なのになかなか認証が通らなかったり、他の人の指で解除できてしまったりということが多々あったので、あんまり信用できないか、精度を上げようとするとお金がかかる技術なのかなぁという印象があったのですが。
Face IDは、人工マスクでもロック解除できないことをテストしました、ということでしたが、サーモグラフィでも見ているんですかね。そのうち例によって顔認証をハックしちゃう人たちが現れるでしょう。

2017/09/13(Wed) 05:21:53

 Heroku/Node.js/ExpressでGitHub Appsのユーザ認証 / magicien 

HerokuでGitHub Appsのユーザ認証をするサンプルコード。
OAuth2を使ったユーザ認証だけ。JWTを使ってリポジトリを操作するのは別途。


  • セキュリティに関わるコードはなるべく自作しないのがセオリーということでpassport-github2を使ってみる。
  • client_id、client_securityはHerokuの環境変数に設定しておく。
  • GitHubStrategyのオプションに state: true を設定し忘れると、はまちちゃんが遊びに来る。
  • stateには24文字のランダムな文字列が設定される。
  • Herokuの場合、sessionのオプションは secure: 'auto'、proxy: true にしないとCookieが発行されない。参考:connectのセッションミドルウェアのcookieのsecure属性について
  • 各モジュールのバージョン:
    • express:4.15.4
    • express-session:1.15.5
    • passport:0.4.0
    • passport-github2:0.1.10

2017/09/11(Mon) 18:49:06

 GitHub AppsでOrganizationにリポジトリを新規作成する / magicien 

GitHub Appsでは、今のところユーザ用リポジトリの作成ができない。Organization用であれば作成できるようなので、作成までの手順をメモしておく。

事前準備

Appの作成とJWT生成の準備は「GitHub Appsでリポジトリにファイル追加・更新」と同様に済ませておく。

操作対象のOrganizationを決める

これも前回とほぼ同じなので流れだけ簡単に書いておく。

ユーザを判別する

ユーザに下記URLへアクセスしてもらう。
https://github.com/login/oauth/authorize?child_id=ChildID&redirect_uri=自分のサイトのどこか&state=ランダムな文字列

戻ってきたリダイレクト先でcodeを取得する。
https://自分のサイト/どこかのページ.html?code=1234567890abcdef&state=先ほどのstate

アクセストークン生成

curl -X POST -d "code=先ほどのcode" -d "client_id=ClientID" -d "client_secret=ClientSecret" https://github.com/login/oauth/access_token

応答からアクセストークン取得
access_token=アクセストークン&scope=&token_type=bearer

ユーザが管理していてAppをインストール済みのOrganizationを取得する

取得方法はユーザのリポジトリを見つけるときと同じ。
curl -H "Authorization: token アクセストークン" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/user/installations

Organization用のInstallationは、target_typeがOrganizationになっている(ユーザ用はUserになっている)。
{
  "total_count": 1,
  "installations": [
    {
      "id": 56789,
      "account": {
        "login": "Organization名",
        中略
      },
      中略
      "integration_id": 1234,
      "app_id": 1234,
      "target_type": "Organization",
      中略
    }
  ],
  "integration_installations": [
    {
      "id": 56789,
      "account": {
        "login": "Organization名",
        中略
      },
      中略
      "integration_id": 1234,
      "app_id": 1234,
      "target_type": "Organization",
      中略
    }
  ]
}
installations[i].app_id が一致し、target_typeがOrganizationのものを見つける。 必要なのは、id(installationのid)とaccount.login(Organization名)。

Installationとしての認証

ここは前回と同じ。
curl -X POST -H "Authorization: Bearer JWTのトークン" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/installations/先ほど取得したinstallationのid/access_tokens

応答も同じ。
{
  "token": "アクセストークンその2",
  "expires_at": "2017-01-01T00:00:00Z"
}

リポジトリを生成する

公式の説明はここ。
最低限必要なパラメータはnameだけ。
curl -X POST -H "Authorization: token アクセストークンその2" -H "Accept: application/vnd.github.machine-man-preview+json" -d '{"name": "リポジトリ名"}' https://api.github.com/orgs/Organization名/repos

おしまい!

2017/09/10(Sun) 17:09:58

 GitHub Appsでリポジトリにファイル追加・更新 / magicien 

GitHub Appsでリポジトリにファイル追加・更新する手順メモ。ゲームエディタの編集データをGitHubに保存したいと思ったので。手元のMacBook Airの空き容量は500MBくらいで虫の息。シンクライアント的な使い方しかできない状態なのです。

はじめに。GitHub Appsで新規リポジトリを作ろうとしたけどだめだった。ユーザ側でAppを使うリポジトリを決める必要があるので、App側で勝手にリポジトリを追加することはできないのかも。OAuth Appsなら作成できるはずなので、やるとすれば、一旦OAuthで作成してから、GitHub Appでそのリポジトリをアクセス対象に追加する感じかな(Appが2つ必要だとするとユーザ側の操作もかなり面倒なことに...)よくよく見たら、APIの説明に「Currently, only the organization endpoint is enabled for GitHub Apps.」って書いてあったぁぁぁ。Organizationで試してみたら問題なくリポジトリ作れたぁぁぁ。ゲームエディタ用Organization作ってそこでリポジトリ管理することにしよう。その方が安全だし。

GitHub Apps作成

ここら辺はずいぶん前の話で忘れてしまったため適当。

Developer Memberに登録

事前にメンバー登録が必要だったと思う。登録に手間取った記憶がないので、要求されたものを入力しただけだったはず。

App作成

ここの手順通りに実施したはず。
登録手順の前に、GitHub AppsとOAuth Appsの二種類があって、こんな違いがありますよーみたいな話が延々と書いてあって手順を見つけるのに苦労した。

App情報を確認

「Setting > GitHub Apps > アプリ名」を選ぶと、アプリ情報の一覧が表示される。最下部にある「OAuth credentials」の「Client ID」「Client secret」を認証に使うので覚えておく。
「Private key」も必要なので、「Generate private key」ボタンを押して生成、覚えておく。

認証用トークン生成準備

認証には JSON Web Token(JWT)なるものを使うので、それを生成する何らかの仕組みを用意する必要がある。
JWTのページにライブラリがたくさんあるので、良さげなものを選ぶ。
自分はサーバでPHPを使っているので、lcobucci/jwtにした。
JWT生成コードはこんな感じ。 Private Keyはボタンを押して生成したものを貼り付け。setIssuerに指定するIDは「Settings > GitHub Apps」で見られる。
有効期限は最大10分なので、手動でのんびり実行していると時間切れになってしまう。

作ったAppのインストール

もしかしたらアプリ生成の時にインストール先を選択済みかも。インストールしていない場合は、
「https://github.com/apps/アプリ名」にアクセスすると、インストールできる。

操作対象のリポジトリを決める

ユーザを判別する

まずは誰がAppを使おうとしているのか判別する。公式の説明はここ
ユーザに下記URLにGETでアクセスしてもらう。(child_idはApp登録時にメモしたもの)

stateはリクエストフォージェリ対策で付けておくと良さげ。何か情報を受けわたす為に使っても良い、とのこと。
https://github.com/login/oauth/authorize?child_id=ChildID&redirect_uri=自分のサイトのどこか&state=ランダムな文字列

すると、アプリが認証を要求してるけど?というページが表示される。ユーザが「良いよ!」ということであれば、redirect_uriで指定したURLに戻ってくる。が、この時、codeパラメータが追加されている。stateが先ほど付けたものと同じかどうかをチェックすると良さげ。
https://自分のサイト/どこかのページ.html?code=1234567890abcdef&state=先ほどのstate

アクセストークン生成

ここから先はサーバ・GitHub間でゴリゴリする。
先ほど返ってきたcodeを使ってアクセストークンを生成する。(JWTを使った認証とは別なので要注意)

curl -X POST -d "code=先ほどのcode" -d "client_id=ClientID" -d "client_secret=ClientSecret" https://github.com/login/oauth/access_token

一応、redirect_urlで次のリダイレクト先を指定できるけど、クライアント側からclient_secretを送ることは無いと思うので使い道なさげ。stateも指定できるけど同じ理由で使い道無さげ(GitHub側でcodeとstateの組をチェックしている様子は無かった)。応答はこんな感じで返ってくる。
access_token=アクセストークン&scope=&token_type=bearer

ユーザが使っているApp(Installation)のIDを取得する

Github AppのIDとは別に、ユーザ・App毎にIDが割り当てられているので、それを取得する。
現状、Acceptヘッダを付けないと怒られるけど、そのうち要らなくなるはず。
curl -H "Authorization: token アクセストークン" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/user/installations
応答はJSONで返ってくる。
{
  "total_count": 1,
  "installations": [
    {
      "id": 56789,
      中略
      "integration_id": 1234,
      "app_id": 1234,
    }
  ],
  "integration_installations": [
    {
      "id": 56789,
      中略
      "integration_id": 1234,
      "app_id": 1234,
    }
  ]
}
installations[i].app_id が一致するものを見つけて、installations[i].id を取得する。integration_installationsに全く同じ情報が入ってるんだけど、どっちを見るべきかよくわからん。

アクセスできるリポジトリ一覧を取得する

先ほど取得したinstallationのidを使って、リポジトリ一覧を取得する。
アプリとしては、ユーザに一覧を表示して選んでもらう感じになると思う。
curl -H "Authorization: token アクセストークン" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/user/installations/さっき取得したinstallationのid/repositories
応答はJSONで返ってくる。今回は repositories[].full_name が分かれば良い。
{
  "total_count": 1,
  "repositories": [
    {
      "id": リポジトリID,
      "name": "リポジトリ名",
      "full_name": "ユーザ名/リポジトリ名",
      中略
    }
  ]
}

Installationとしての認証

これ要る?公式の説明はここ
先ほど取得したアクセストークンだとリポジトリ操作ができないようなので、Installation用のアクセストークンを別途取得する。
最初の方で準備しておいたJWTのトークンを生成して、次のコマンドを実行する。
curl -X POST -H "Authorization: Bearer JWTのトークン" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/installations/先ほど取得したinstallationのid/access_tokens
応答はJSONで返ってくる。
{
  "token": "アクセストークンその2",
  "expires_at": "2017-01-01T00:00:00Z"
}

ファイルを追加する

ようやくファイルを追加する。公式の説明はここ
curl -X PUT -H "Authorization: token アクセストークンその2" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/repos/ユーザ名/リポジトリ名/contents/ファイルパス -d '{"path":"ファイルパス","message":"commitメッセージ","content":"ファイルの内容"}'
オプションでcomitterの情報も付けられる。デフォルトだと、Appのbotがcomitterになる。branchでブランチの指定も可。
contentはbase64にエンコードしないといけないので、base64コマンドを使うなりして変換しておく。

ファイルを更新する

ファイルを追加する場合とほぼ同じ。唯一の違いは、元のファイルのshaを指定すること。

元ファイルのshaを取得する

認証トークンは特に要らない。
curl https://api.github.com/repos/ユーザ名/リポジトリ名/contents/ファイルパス
応答はJSON形式。
{
    中略
    "sha": "ハッシュ値",
    中略
}

ファイル更新

curl -X PUT -H "Authorization: token アクセストークンその2" -H "Accept: application/vnd.github.machine-man-preview+json" https://api.github.com/repos/ユーザ名/リポジトリ名/contents/ファイルパス-d '{"path":"ファイルパス","message":"commitメッセージ","content":"ファイルの内容", "sha":"ハッシュ値"}'

2017/09/10(Sun) 09:04:16

 Undo/RedoできるCanvasを作った / magicien 

まーた言ったそばから脇道に逸れているわけ。
HTMLCanvasElement (CanvasRenderingContext2D) に undo/redo機能が欲しいな、と思ったので作りました。
undo-canvasデモページ1

CanvasRenderingContext2Dのプロパティに片っ端からフックをかますという荒技を使い、変更したプロパティ、呼び出したメソッドを全て記録しています。
副産物として、上書きしたメソッドを prototype で定義されているものに戻す reset-object を別モジュールとして作りました。

使ってみたい人は、scriptタグでundo-canvasを読み込んでください。
<script src="https://cdn.rawgit.com/magicien/undo-canvas/v0.1.2/undo-canvas.js"></script>
ブラウザ向けnpmモジュールを作っている人は、npmコマンドでインストールできます。
npm install --save undo-canvas
jsファイルを読み込むと、グローバル変数として UndoCanvas が定義されるので、
const canvas = document.getElementById('myCanvas')
const context = canvas.getContext('2d')
UndoCanvas.enableUndo(context)
こんな感じで、UndoCanvas.enableUndoにコンテキストを引数として渡してください。contextに undo/redo 関数が追加され、以降、このcanvasに対する操作が記録されていきます。
undo/redoしたくなったら、
context.undo()
context.redo()
で行ったり来たりできます。
undo/redoが必要なくなったら、disableUndoで無効化できます(記録されていた操作履歴は全て消えます)。
UndoCanvas.disableUndo(context)
その他機能はGithubの記載を更新していくので、そちらを参照してください。

undo/redoを実現する仕組みはOracleのようなDBの考え方をぱく参考にしたのですが、思いの外うまくハマったので、気が向いたら解説記事でも書くかもしれません。

さて、今度こそエディタ制作作業に戻ろう...

2017/09/06(Wed) 04:58:25