ブログサービスからPingを受け取る
2018年になってもブログサービスからPingで更新通知を受け取っています。。 XML-RPCでWordPress等のブログから更新通知を受け取れるのですがまた探すかもしれないのでメモ。
weblogUpdates.ping
詳細は weblogUpdates.extendedPing
を参照
<?xml version="1.0" encoding="UTF-8"?> <methodCall> <methodName>weblogUpdates.ping</methodName> <params> <param> <value>Someblog</value> </param> <param> <value>https://example.com/someblog</value> </param> </params> </methodCall>
weblogUpdates.extendedPing
パラメーター
- サイト名
- ウェブサイトのURLもしくはRSSフィードのURL
- (weblogUpdates.pingではOptional) ページのURL
- (weblogUpdates.pingではOptional) RSS/RDF/AtomフィードのURL
- (Optional) カテゴリーまたはタグ名,
|
区切り
<?xml version="1.0" encoding="UTF-8"?> <methodCall> <methodName>weblogUpdates.extendedPing</methodName> <params> <param> <value>Someblog</value> </param> <param> <value>https://example.com/someblog</value> </param> <param> <value>https://example.com/someblog/entries/1111</value> </param> <param> <value>https://example.com/someblog/feed.rss</value> </param> <param> <value>personal|friends</value> </param> </params> </methodCall>
WordPressからはweblogUpdates.ping
とweblogUpdates.extendedPing
が同時に送られてくるのを見たことがある。
出典:
LinuxからSoftEther VPNサーバ(SSL VPN)へ接続したあとの使い方
接続した後にどうするのかわからなくて苦戦したのでメモ。
環境は
- クライアント側:
SoftEther VPN Version 4.25 Build 9656
,Linux healthy 4.15.18-1-MANJARO #1 SMP PREEMPT Thu Apr 19 09:05:40 UTC 2018 x86_64 GNU/Linux
- サーバ側: GithubのSoftEtherVPN_Stableのmaster
目的: 設定済みのSoftEther VPNサーバへvpnazure.net経由でNATを超えて接続する。ゲートウェイにはせずにVPN内のホストにIPアドレス直打ちでアクセスしたい。
SSL VPNで、サーバ側はNATの中にある状態。なんと、vpnazure.netが使える。(SSTP専用かと思いきや)
vpncmd
でアカウントを設定しておきます。ホスト名にvpnazure.net
のホスト名を使用する。(素晴らしい)
仮想NIC名はVPN
で作成。
VPNへ接続
$ vpncmd /client localhost /CMD AccountConnect <アカウント名>
IPアドレスを割り当てる。デフォルトゲートウェイには追加せず、/etc/resolv.confも書き換えないようにする。
# ip link set vpn_vpn down
# ip link set vpn_vpn up
# dhcpcd -G -C resolv.conf vpn_vpn
# ip route add 192.168.100.0/24 via 192.168.30.1 dev vpn_vpn # VPN経由でアクセスしたいネットワークを指定
以上
VPNから切断
$ vpncmd /client localhost /CMD AccountDisconnect <アカウント名>
IPアドレスの割り当てを削除
# ip link set vpn_vpn down
# ip link set vpn_vpn up
# dhcpcd -k vpn_vpn
Go言語で埋め込みをしたstructでのjson.UnmarshalJSON
goを書いていて、部分実装やゆるふわなJSONを扱うためにstructの埋め込みを使うことがある。 そのstructに対してJSONを読み込む時に少しハマった事があるのでメモ。
まずはじめに、こんな具合でJSNONをOuter
にマッピングしていた。
https://play.golang.org/p/zGo779zhxI
package main import ( "encoding/json" "fmt" ) type Outer struct { InnerA InnerB } type InnerA struct { FieldA string `json:"a_field"` } type InnerB struct { FieldB string `json:"b_field"` } func main() { var v Outer data := []byte(`{"a_field": "A", "b_field": "B"}`) if err := json.Unmarshal(data, &v); err != nil { fmt.Println("[Error] " + err.Error()) return } fmt.Printf("%+v", v) // {InnerA:{FieldA:A} InnerB:{FieldB:B}} }
開発中にJSONのb_field
が文字でないfalseを返す場合があることが分かってしまったので以下の様に対応した。
https://play.golang.org/p/0WszSKVN0m
package main import ( "encoding/json" "fmt" ) type Outer struct { InnerA InnerB } type InnerA struct { FieldA string `json:"a_field"` } type InnerB struct { FieldB string `json:"b_field"` } func (e *InnerB) UnmarshalJSON(data []byte) error { var v struct { FieldB interface{} `json:"b_field"` } if err := json.Unmarshal(data, &v); err != nil { return nil } switch v.FieldB.(type) { case string: break default: return nil } e.FieldB = v.FieldB.(string) return nil } func main() { var v Outer data := []byte(`{"a_field": "A", "b_field": "B"}`) if err := json.Unmarshal(data, &v); err != nil { fmt.Println("[Error] " + err.Error()) return } fmt.Printf("%+v", v) // => {InnerA:{FieldA:} InnerB:{FieldB:B}} }
これで上手くいくと思いきや、InnerA
のフィールドがゼロ値になってしまっている。
そこで、面倒だけどOuter
でそれぞれUnmarshalすることでなんとかなった。
https://play.golang.org/p/kii9ZmoX1O
package main import ( "encoding/json" "fmt" ) type Outer struct { InnerA InnerB } type InnerA struct { FieldA string `json:"a_field"` } type InnerB struct { FieldB string `json:"b_field"` } func (e *Outer) UnmarshalJSON(data []byte) error { var err error err = json.Unmarshal(data, &e.InnerA) if err != nil { return err } err = json.Unmarshal(data, &e.InnerB) if err != nil { return err } return nil } func (e *InnerB) UnmarshalJSON(data []byte) error { var v struct { FieldB interface{} `json:"b_field"` } if err := json.Unmarshal(data, &v); err != nil { return nil } switch v.FieldB.(type) { case string: break default: return nil } e.FieldB = v.FieldB.(string) return nil } func main() { var v Outer data := []byte(`{"a_field": "A", "b_field": "B"}`) if err := json.Unmarshal(data, &v); err != nil { fmt.Println("[Error] " + err.Error()) return } fmt.Printf("%+v", v) }
理由は後で調べる。
WordPress ACF to REST APIで関連記事のアイキャッチ画像を含める
あるサービスの一部がライターさんに直接使ってもらいたいという理由でバックエンドにWordPressを使っている。 最近のWordPressは良くできていて標準でREST APIが叩けるので別のシステムから扱うのが随分楽になった。
別システムから使うため、いろいろな設定項目をWordPress側から変更できるようにしていて、それを実現するためにAdvanced Custom Fields(以下ACF)というプラグインを導入してカスタムフィールドとして本文やタイトル以外の設定ができるようにしている。界隈では結構有名だったと思う。 ただ、ACFを入れるだけではREST APIにカスタムフィールドが出てこないので、さらにACF to REST APIというプラグインも導入している。
ACFではある投稿に対して、別の投稿を紐付けるカスタムフィールドを定義することができ、relations
と呼ばれる。
REST APIである投稿を取得すると、acf
というキーで各種カスタムフィールドがまとめられて返ってくるのだが、そこにはアイキャッチ画像が無い。
本体の記事はfeatured_media
というキーでIDが取得でき、GETパラメータに_embed
を含めるとレスポンスの_embedded.wp:featuredmedia
に画像の詳細が含まれてレスポンスされ、その中に各サイズごとにサイズ, URLなどが含まれる。
そこで、ACF to REST APIのフックを利用して、関連記事に対しても_embed
で画像の情報を含める事ができるようにした。
add_filter( 'acf/rest_api/post/get_fields', 'includeACFFieldsInRESTRelation', 10, 3); function includeACFFieldsInRESTRelation( $data, $request, $response ) { if ( $response instanceof WP_REST_Response ) { $data = $response->get_data(); } remove_filter('acf/rest_api/post/get_fields', 'includeACFFieldsInRESTRelation', 10); if (!empty($data)) { array_walk_recursive($data, 'shallowIncludeACFFields', array('post')); } add_filter( 'acf/rest_api/post/get_fields', 'includeACFFieldsInRESTRelation', 10, 3); return $data; } function shallowIncludeACFFields( &$item, $key, $postTypes, $level=0, $post ) { if (isset( $item->post_type ) && in_array( $item->post_type, $postTypes )) { // アイキャッチ画像が設定されていればIDを`featured_media`に入れる if($media_id = get_post_thumbnail_id($item->ID)) { $item->featured_media = intval($media_id, 10); } // `_embed`の場合は`_embedded`内に画像のメタデータを入れる if(isset($_GET['_embed']) && isset($item->featured_media)) { $media = get_post($media_id); $server = rest_get_server(); $controller = new WP_REST_Posts_Controller($media->post_type); $post_type = get_post_type_object($media->post_type); $request = WP_REST_Request::from_url(rest_url(sprintf('wp/v2/%s/%d', $post_type->rest_base, $media->ID))); $request['context'] = 'embed'; $response = $server->dispatch($request); $response = apply_filters('rest_post_dispatch', rest_ensure_response($response), $server, $request); $item->_embedded = array(); $item->_embedded['wp:featuredmedia'] = array(); $item->_embedded['wp:featuredmedia'][] = $server->response_to_data($response, isset($_GET['_embed'])); } // ACFのフィールドも入れる if($fields = get_fields($item->ID)) { foreach($fields as $key => $value) { $item->acf = $fields; } } } }