2017年7月2日日曜日

Cocoapods で「ERROR: Parsing unable to continue due to parsing error」

概要

pod install などするときにタイトルのエラーが発生してインストールなどができなくなりました
エラーの詳細は以下の通りです

[!] ERROR: Parsing unable to continue due to parsing error:
contained in the file located at /Users/kakakikikeke/.cocoapods/repos/master/CocoaPods-version.yml
---
min: 1.0.0
last: 1.3.0.beta.2
prefix_lengths:
- 1
- 1
- 1

対応方法を紹介します

環境

  • mac OS X 10.12.5
  • Cocoapod 1.2.1
  • Xcode 8.3.3 (8E3004b)

対応方法

  • gem uninstall psych

で自分は解決しました
正直理由は不明です

2017年6月30日金曜日

Firebase で Database を使う方法

概要

前回 アノニマス認証の方法を紹介しました
今回は認証後に Firebase のリアルタイム Database にアクセスしてみたいと思います
データベースのルールを変更することで認証しているかどうかでアクセスできるかできないかも検証してみます

環境

  • macOS X 10.12.5
  • Xcode 8.3.3 (8E3004b)
  • Firebase/Core/Auth/Database 4.0.2

データベースへのアクセスルール

とりあえず以下のように設定します

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}

このルールは「どんなアカウントでもいいので認証済み」であれば read も write もできるルールになります

データベースに保存する

  • ViewController.swift
import UIKit
import Firebase
import FirebaseAuth
import FirebaseDatabase

class ViewController: UIViewController {

    var ref: DatabaseReference!

    override func viewDidLoad() {
        super.viewDidLoad()
        Auth.auth().signInAnonymously(completion: { (user, error) in
            if let e = error {
                print(e)
                print("login error")
                return
            }
            print(user?.displayName ?? "no displayName")
            print(user?.isAnonymous ?? false)
            self.ref = Database.database().reference()
            // データの保存
            self.ref.child("users").setValue(["username": user?.uid])
        })
    }
}

データベースを参照するための変数「ref」を定義しておきログイン後に接続します (Database.database().reference())
そして ref.child.setValue を使ってデータを保存します
認証に成功するとデータベースに write する権限があるため以下のようにデータが投入されます
firebase_anonymous3.png

権限を変更して挙動を確認する

次に write の権限を変更してみます

{
  "rules": {
    ".read": "auth != null",
    ".write": false
  }
}

false に変更しました
こうすることでデータベースに対してどんなユーザでもアクセスできなくなります
実際にアプリをビルドし直して試してみるとコンソールに

<Warning> [Firebase/Database][I-RDB038012] setValue: or removeValue: at /users failed: permission_denied

というデバッグ文が出力されているのがわかると思います

データを取得する

ついでに取得もやってみましょう
* ViewController.swift

// データの取得
self.ref.child("users").observeSingleEvent(of: .value, with: { (snapshot) in
    print(snapshot.value ?? "no value")
})

を保存の下に追記すれば OK です
今回は observeSingleEvent を使いました
リアルタイム Database にはイベントドリブンでデータを取得する方法もありデータが追加されたらイベントが発行され、その都度何か処理する方法もあります

その辺りの方法は参考サイトの URL を参考に試してみてください
やり方はほとんど同じようにできると思います

最後に

Firebase のリアルタイム Database を使ってみました
また今回は使いませんでしたが、イベントドリブンな取得もできるのでチャットアプリなどの開発が捗る機能かなと思います

参考サイト

2017年6月29日木曜日

Firebase で Anonymous 認証を使う方法

概要

Firebase のアノニマス認証を使ってみました
簡単な利用方法を紹介します

環境

  • macOS X 10.12.5
  • Xcode 8.3.3 (8E3004b)
  • Firebase/Core/Auth 4.0.2

Firebase 側の設定

デフォルトではアノニマス認証はオフになっていて使えません
Firebase のコンソールにログインして有効にする必要があります

Authentication -> ログイン方法 (タブ) -> 匿名

で有効にします
firebase_anonymous1.png

また、アプリの GoogleService-Info.plist をダウンロードしてプロジェクトにコピーしてください
firebase_anonymous2.png

ライブラリインストール

  • pod init
  • vim Podfile
target 'firebase-test' do
  use_frameworks!

  # Pods for firebase-test
  pod 'Firebase/Core'
  pod 'Firebase/Auth'
end
  • pod install

初期化

  • AppDelegate.swift
import UIKit
import CoreData
import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        FirebaseApp.configure()
        return true
    }
    // 途中省略...
}

import して FirebaseApp.configure() を実行します

ログイン認証

本題です

  • ViewController.swift
import UIKit
import Firebase
import FirebaseAuth

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        Auth.auth().signInAnonymously(completion: { (user, error) in
            if let e = error {
                print(e)
                print("login error")
                return
            }
            print(user?.displayName ?? "no displayName")
            print(user?.isAnonymous ?? false)
        })
    }
}

signInAnonymously を呼ぶ感じです
completion のコールバックメソッドにログイン後のユーザ情報 or エラー情報が返ってきます

最後に

Firebase のアノニマス認証の方法を紹介しました
認証のあとにデータベースなどにアクセスするロジックを実装する感じです

Swift の Firebase のライブラリは現在バージョン 4 ですが、3 から上がった時に非互換な部分が多かったようでググって出たページが古いとクラスがなかったり関数がなかったりと動作しないケースが多かったです
公式のドキュメントですら古いケースがあったので Xcode の補完を使ったりコードを直接見ると良いかもしれません

参考サイト

2017年6月28日水曜日

StackEdit で Google ドライブに保存使用したら「Unable to authenticate user xxxxxxxxxxx, please sign in with Google.」が出た

概要

作成した Markdown を Google ドライブに保存しようとしたらタイトルのエラーが発生しました
対応方法を紹介します

環境

  • Windows7
  • Firefox 53.0.3

対応方法

この作業は StackEdit に関するローカルストレージの情報をすべて削除してるので Markdown の記事の情報も削除されます
なので、事前に Markdown の情報はどこかに退避しておいてください

  1. https://stackedit.io/recovery.html にアクセスします
  2. 「StackEdit local storage.json」をダウンロードします
  3. Menu -> Settings -> Utils -> Import docs and settings で先程ダウンロードした json を開きます
  4. 再度 https://stackedit.io/recovery.html の画面に戻り「To remove one document from the local storage click here.」の click here をクリックします
  5. 同様に「To fully clear the local storage click here.」の click here をクリックします
  6. 「To reopen StackEdit click here.」のクリックして再度 StackEdit を開きます

これで再度 Google ドライブに保存してみてください
成功するはずです

最後に

原因おそらくは複数のユーザを使い分けようとしてるのが原因かなと思います
例えば昔 Firefox で StackEdit を使っていて、そのとき利用してた Google アカウントではないアカウントで今回利用とすると該当のエラーが発生すると思います
認証情報が過去のユーザのものになっているのでエラーが発生していた感じだと思います

2017年6月27日火曜日

VMware Harbor の REST API を有効にしてプロジェクトやユーザに API でアクセスしてみる

概要

VMware Harbor の管理画面で実行されているライブラリやユーザ作成はバックエンドでは API 経由で実行されています
実はこの API は利用者側からも使用することができます
デフォルトではオフになっているので有効にすることで使用できるようになります

環境

  • Ubuntu 16.04
  • Harbor 1.1.1
  • docker-compose 1.13.0
  • docker 17.03

事前作業

Harbor のインストールはオフラインインストールを使って Ubuntu 上にインストールしています
手順はこちらの記事を参考にしてください

REST API の有効化

Harbor が動作しているサーバにログインしてサーバ上で作業する必要があります
harbor は /root/harbor にインストールしているものとします

  • cd /root/harbor
  • wget https://raw.githubusercontent.com/vmware/harbor/master/docs/prepare-swagger.sh https://raw.githubusercontent.com/vmware/harbor/master/docs/swagger.yaml
  • vi prepare-swagger.sh
SCHEME=https
SERVER_IP=reg.your.domain

ここのスキーマとサーバの設定の部分は http で IP ベースで動作している場合は、それを入力してください
ドメインを貼って証明書まで設定してる場合は、https で Harbor に設定したドメインを入力してください

  • chmod +x prepare-swagger.sh
  • ./prepare-swagger.sh

シェルを実行するとカレントに swagger.tar.gz が作成されているはずです

  • cp docker-compose.yml{,.back}
  • vi docker-compose.yml
- ../src/ui/static/vendors/swagger-ui-2.1.4/dist:/harbor/static/vendors/swagger
- ../src/ui/static/resources/yaml/swagger.yaml:/harbor/static/resources/yaml/swagger.yaml

上記 2 行を「ui:」の「volumes:」の部分に追記します
diff だと以下の通りになります

  • diff docker-compose.yml.back docker-compose.yml
79a80,81
>       - ../src/ui/static/vendors/swagger-ui-2.1.4/dist:/harbor/static/vendors/swagger
>       - ../src/ui/static/resources/yaml/swagger.yaml:/harbor/static/resources/yaml/swagger.yaml

あとはコンテナを再起動すれば OK です

  • docker-compose down
  • docker-compose up -d

動作確認

まず https://reg.your.domain/static/vendors/swagger/index.html にアクセスして Swagger UI が表示されることを確認してください
ここで UI が表示されないと API が有効になっていません

表示されたら実際に API をコールしてみましょう
例えばプロジェクトやリポジトリを検索する API /search は以下のようにコールできます

  • curl -X GET --header 'Accept: application/json' 'https://reg.your.domain/api/search?q=library'

結果以下のような json が返却されれば OK です

{
  "project": [
    {
      "project_id": 1,
      "owner_id": 1,
      "name": "library",
      "creation_time": "2017-06-26T08:03:45Z",
      "creation_time_str": "",
      "deleted": 0,
      "owner_name": "",
      "public": 1,
      "Togglable": false,
      "update_time": "2017-06-26T08:03:45Z",
      "current_user_role_id": 0,
      "repo_count": 0
    }
  ],
  "repository": []
}

SDK や詳しいドキュメントはほぼないので、Swagger UI を見ながら API をコールするしかないと思います
swagger.yaml が公開されているので go-swagger を使って swagger generate client すればクライアントツールは簡単に作れるかもしれません

最後に

Harbor の REST API を有効にしてプロジェクトやレジストリの情報にアクセスできるようにしてみました
認証等は特になかったので公開するのは少し危険ですが、プライベートで独自の UI を作ったりするには便利かなと思います

参考サイト

2017年6月23日金曜日

Arduino でバイト配列を文字列に変換する方法

概要

タイトルの通り
MQTT の PubSubClient.h を使う時にペイロードが byte* だったので文字列に変更したかった感じです

環境

  • macOS 10.12.5
  • Arduino IDE 1.6.12

コード

void callback(char* topic, byte* payload, unsigned int length) {
  payload[length] = '\0';
  String msg = String((char*) payload);
  Serial.println(msg);
  if (msg == "start") {
    // something ...
  } else if (msg == "stop") {
    // something ...
  }
}

ポイントはバイト配列の最後に終端文字を入れてること
こうしないとうまく文字列に変換できません

最後に

*byte を String に変換する方法を紹介しました
久しぶりに Arduino に触るとよくわかんないですね

参考サイト

2017年6月22日木曜日

firebase-ruby の get, push, set, update, delete の挙動を確認してみた

概要

前回 は firebase-ruby を使った GettingStarted 的な記事を紹介しました
今回はリアルタイムデータベースを操作できるその他のメソッドについて挙動を確認してみました

環境

  • CentOS 7.3.1611
  • ruby 2.3.3p222
  • firebase-ruby 0.2.6

使用するコード

  • bundle init
  • vim Gemfile
gem "firebase"
  • bundle install
  • vim test.rb
require 'firebase'

class FB
  BASE_URI = 'https://project-id.firebaseio.com/'
  SECRET_KEY = 'your-database-secret-key'

  def initialize
    @client = Firebase::Client.new(BASE_URI, SECRET_KEY)
  end

  def get(path, query)
    @client.get(path, query)
  end

  def push(path, hash)
    @client.push(path, hash)
  end

  def set(path, hash)
    @client.set(path, hash)
  end

  def update(path, hash)
    @client.update(path, hash)
  end

  def delete(path, query)
    @client.delete(path, query)
  end
end

f = FB.new

res = f.push('test', { :name => "hoge" })
id = res.body['name']
res = f.get("test/#{id}", {})
p res.body['name'] # => "hoge"

f.set('test1', { :name => "fuga" })
res = f.get('test1', {})
p res.body['name'] # => "fuga"

f.update("test/#{id}", { :name => "hogehoge" })
res = f.get("test/#{id}", {})
p res.body['name'] # => "hogehoge"
f.update('test1', { :name => "fugafuga" })
res = f.get('test1', {})
p res.body['name'] # => "fuga"

f.delete("test/#{id}", {})
f.delete('test1', {})
  • bundle exec ruby test.rb

BASE_URI と SECRET_KEY は自分のプロジェクトの値を設定してください

挙動説明

firebase-ruby にはデータを登録するためのメソッドが 2 つ用意されています
push と set があります

push の場合、基本的に毎回新規オブジェクトの追加となります
追加したオブジェクトに自動で ID を振ってくれるため、その ID でオブジェクトを識別します
ID は push したレスポンス情報に含まれています

方や set は指定したパスにそのままデータを登録します
なので 2 回 set しても内容は変わりません、オブジェクトも増えません
get でアクセスする場合のパスにも ID が含まれることはありません

get は path を指定してデータを取得します
path 配下にあるオブジェクトに対して絞り込みを行いたい場合はクエリを使います
https://firebase.google.com/docs/reference/android/com/google/firebase/database/Query
例えば上位 10 件のみを取得したい場合は limit を使います

あとは update と delete ですが、これも path で取得したオブジェクト配下の情報を削除したり更新したりします
update に関しては上書き更新なのでデータが新規で登録されるということはありません
delete に関しては物理削除なので、一度削除したオブジェクトは再度戻すことはできません

最後に

firebase-ruby が用意している関数の挙動を確認してみました
個人的には push ではなく set を使ってデータ登録したほうが毎回 ID を走査しなくて済むので簡単かなと思います

あとは get, update, delete を使って登録したデータを path を指定して操作する感じかなと思います

Firebase のデータベース機能はリアルタイムデータベースなので push や set で登録したときのアプリ側の挙動も確認したいと思っています
また Firebase には他にもストレージやホスティング機能、スクリプト機能があるのですが、firebase-ruby ではデータベース機能に対する制御しかできません
ストレージなどを使いたい場合は直接 Google Storege を操作する感じになるみたいです

参考サイト