7.3 Consumerプログラムの作成 |
---|
2022年4月13日 |
||
FiwareのAPIはNGSIの標準に従った、Web APIと呼ばれるものです。ConsumerやProviderとのインタフェースもこのWeb APIで行います。Web APIを受け付ける機能をWeb Serverと言いますが、これは色々な場面で一般的に使われる機能なので、有償のものから無償のものまで沢山の種類があります。本書では、簡単に構築できることからPythonというプログラミング言語を使ってWeb ServerをPCのWindows上に構築します。 |
||
|
||
|
||
2022年4月13日 |
||
まず、Pythonのサイト にアクセスすると、次のような画面が表示されます。赤点線のところにdownloadとあるので、クリックします。 |
||
そうすると、以下の様にプルダウンメニューが表示されるとともに、下部に各バージョンの一覧が表示されます。Windowsの最新版をクリックしてダウンロードします。ダウンロードしたら、そのexeファイルをダブりクリックすれば、インストールが始まります。 |
||
インストーラの初期画面では、以下の様にオプションが表示されますが、Add Python x.x to PATHはチェックしておいた方が良いです。これをチェックしなくてもPythonは動作しますが、一緒にインストールされるツールがPATH変数に追加されないので、動作させるのに苦労します。但し、自動的に登録してくれるバスは、インストーラーが既定値で持っているインストール先だけの様で、インストール場所を変更するとうまく動作しません。 |
||
インストールが完了したら、以下のような結果になります。 |
||
次に動作確認します。IDLEというツールを起動します。そうすると、以下のようにPythonのGUIが起動します。このままPythonのコードを入力すると、インタプリタとして動作します。 |
||
例えば、以下のような感じです。 |
||
|
||
2022年4月13日 |
||
Subscription用のConsumerやRegistration用のProviderはOrion/Fiwareから呼び出されるので、サーバ側となります。今回はセキュリティの心配がないので 、Pythonからhttp.serverというモジュールを使って簡便に構築します。 | ||
注:http.serverのドキュメントに記載の通り、業務用のシステムには推奨されていません。また、現在はスレッドを使う事ができますが、本書ではマルチスレッドは考慮していません | ||
以下のPythonプログラムをconsumer.pyというファイルに書き込みます。書き込むツールはテキストで書き込めるものであればなんでも良いのですが、筆者は今まで同様メモ帳を使いました。余談ですが、上記のリンクからconsumer.pyをダウンロードする場合はブラウザで開くのではなく、右クリックで一度ダウンロードしてからご利用下さい。そうしないと、日本語が文字化けする事があります。 |
||
import http.server as s from urllib.parse import urlparse #url anslysis module import json class MyHandler(s.BaseHTTPRequestHandler): def do_POST(self): #server_foreverからPOST時に呼ばれる # urlパラメータを取得 parsed = urlparse(self.path) #url文字列を分解してnamed tupleに変換 # urlパラメータを解析 urlpath = parsed.path #パスの文字列を取り出す urldir = urlpath.split('/') # print(urldir) if (len(urldir) < 3 or urldir[1] != "subscriptions"): # 登録したsubscriptionからのPOSTではない print ('Context ConsUmer error (1): invalid resource: ', urlpath) self.send_response(400) #レスポンスのステータスを"Bad request"に設定 self.send_header('Content-length', 0) #ヘッダのcontect-lengthを設定 self.end_headers() #ヘッダの後に空行を出力 self.wfile.write(''.encode()) return() if urldir[2] == 'temperature-change':#temperatureのsubscription content_len = self.headers.get("content-length") #Headerのcontent-lengthの値を採取 if content_len =='': print ('Context Consumer error (2): missing message body') self.send_response(400) self.send_header('Content-length', 0) self.end_headers() self.wfile.write(''.encode()) return() content_len = int(content_len) req_body = self.rfile.read(content_len).decode("utf-8") json_dict = json.loads(req_body) print('部屋 : {}'.format(json_dict['data'][0]['name']['value']['value'])) print('室温 : {}'.format(json_dict['data'][0]['temperature']['value'])) body = '' else: print ('Context Consumer error (3): missing message body') self.send_response(400) self.send_header('Content-length', 0) self.end_headers() self.wfile.write(''.encode()) return() # 返信を組み立て self.send_response(200) #レスポンスのステータスを"正常"に設定 self.send_header('Content-type', 'text/html; charset=utf-8') #ヘッダのcontect-typeを設定 self.send_header('Content-length', '0') #ヘッダのcontect-lengthを設定 self.end_headers() #ヘッダの後に空行を出力 self.wfile.write(body.encode()) #クライアントに応答 def do_GET(self): #server_foreverからGET時に呼ばれる print('Context Consumer error (4): invalid method: GET') self.send_response(400) self.send_header('Content-length', '0') self.end_headers() self.wfile.write(''.encode()) def do_PUT(self): #server_foreverからPUT時に呼ばれる print('Context Consumer error (4): invalid method: PUT') self.send_response(400) self.send_header('Content-length', '0') self.end_headers() self.wfile.write(''.encode()) port = 3000 httpd = s.HTTPServer(("", port), MyHandler) print('Context Consumerを起動しました。ポート:%s' % port) httpd.serve_forever() |
||
このファイルをダブルクリックすると、Python が自動的に起動し、ポート番号3000でリクエストを待ち受けます。この待ち受けを技術的には「listenする」と言います。 試しに、webブラウザから問い合わせてみましょう。問い合わせは、http://localhost:3000です。この時の表示は以下のようになるはずです。 |
||
Context Consumerを起動しました。ポート:3000 Context Consumer error (4): invalid method: GET 127.0.0.1 - - [07/May/2022 14:50:37] "GET / HTTP/1.1" 400 - |
||
Fiware/OrionからContext Consumerに対する通知はPOSTなのですが、ブラウザからはGETでリクエストが発行されるので、Context Consumerはエラーを返却しています。とにかく、ちゃんとポート3000でメッセージが通知されたことは確認できました。 | ||
|
||
今回は、fiware/orionから通知をWindows上のConsumerに送るので、そのための指定を追加します。ネットワークの構成は右以下の図となります。追加されるのは、太い赤字の部分です。 このうち、"hostpc"の部分がコンテナ起動時の指定となります。 まずは、Ubuntuから見たWindowsのIPアドレスを調べます。2.3節で説明したように、Ubuntuで以下のコマンド打ち、nameserverの右側のIPアドレスをメモします。筆者の環境では、172.27.144.1でした。 |
||
cat /etc/resolv.conf | ||
次に、一旦fiware/orionのコンテナを停止します。以下の二つのコマンドが必要です。 |
||
docker stop fiware-orion docker rm fiware-orion |
||
コンテナが停止したら、前記のIPアドレスを指定して以下の様に打ち、コンテナを再起動します。 |
||
docker run -d --name fiware-orion --network=fiware_default --add-host=hostpc:172.27.144.1 -p 1026:1026 fiware/orion -dbhost mongo-db |
||
harry@MSI:~$ docker run -d --name fiware-orion --network=fiware_default --add-host=hostpc:172.27.144.1 -p 1026:1026 fiware/orion -dbhost mongo-db 7bf51ff4b7419ea867140e7bad41c50246a145b8d7bd0ac2a70f5d04e438a034 harry@MSI:~$ |
||
このコマンドの意味は、"fiware/orion"というimageを、バックグランドで動作する"fiware-orion"という名前のContainerとして起動しています。その際に、コンテナが使うネットワークはfiware_defaultです。fiware/orionのコンテナのポート1026はDcokerの外部からも1026で通信可能とします。逆にコンテナ側から外部(Windows)への通信時には、172.27.144.1というIPアドレスを指定する代わりに"hostpc"という名前で呼び出す事を可能とする指定です。また、Orionに必要なDBは"mongo-db"というコンテナを使うように指定しています。 ここで、fiware/orionのContainerからWindowsに通信ができる事を確認しましょう。まずはContainer内からcUrlコマンドを動かせるように、以下のコマンドをUbuntuから発行します。 |
||
docker exec -it fiware-orion bash |
||
そうすると、fiware/orionのContainerのBashが起動します。そこで、以下のcUrlコマンドを発行します。これは、hostpcで指定したIPアドレスのポート番号3000番に対してPOSTの要求をするのですが、その際に7.6節で説明するResistrationに応じてFiware/OrionからContext Providerに対して発行される要求を真似してデータを送信しています。 |
||
curl -X POST -H 'Content-Type: application/json' http://hostpc:3000/subscriptions/temperature-change -d '{"data":[{"id":"aaa","type": "Room","name":{"type":"StructuredValue","value":{"type":"Text","value": "bbb"}},"temperature":{"type":"StructuredValue","value":100}}]}' | ||
harry@MSI:~$ docker exec -it fiware-orion bash bash-4.4$ curl -X POST -H 'Content-Type: application/json' http://hostpc:3000/subscriptions/temperature-change -d '{"data":[{"id":"aaa","type": "Room","name":{"type":"StructuredValue","value":{"type":"Text","value": "bbb"}},"temperature":{"type":"StructuredValue","value":100}}]}' bash-4.4$ |
||
そうすると、Providerのプログラムには以下の様なメッセージが表示されれば、正常に通信が行われていることが分かります。 | ||
部屋 : bbb 室温 : 100 172.22.32.1 - - [07/May/2022 15:14:37] "POST /subscriptions/temperature-change HTTP/1.1" 200 - |
||