
入金
Freeswitchが私の小さな弱点であることがたまたま起こりました。 はい、現在、アスタリスクは世界でより広く普及しており、私もそれをよく知っていますが、... Freeswitchは何かで私を魅了します。 機能のセット、おそらく非常に安定した動作、リソース消費の低さ、そしてより論理的なデバイスかもしれません。 または、私はIT業界のヒップスターであり、他の人とは違っていたらよかったと思います。 知る方法。 私たちは人間の魂の闇を掘り下げる心理学者ではないので、私たちはそれを当たり前のことと思って、より実用的なことをしています。 カスタマーサービスを改善します。 議題に彼の認識を通じて改善されたクライアントの個人化です。
雑学
電話帳は完全に実用的です。 IPテレフォニーシステム上の多かれ少なかれすべてのアドオンに存在します。 着信コールが電話番号でクライアントを識別することを許可します。 もちろん、私たちは営業部門ではありません。CRMで全員を書くわけではありませんが、問題を抱えてテクニカルサポートに電話をかける顧客従業員であっても、すぐに認められます。 アプリケーションレベルでは、電話帳は通常プラグインとして接続され、特定のインフォメーションストア(ほとんどの場合はデータベース)をデータソースとして使用できます。 私は同様の運命とFreeswitchを逃れませんでした。 異なる時間に、電話帳に2つのオプションを使用しました。
- プラグインとSQLiteデータベースに基づいています。
- Luaの自己記述RESTコネクタに基づいています(今日使用)。
両方のオプションの実装について説明します。 それぞれに長所と短所があります。
データベースの電話帳は、デバイス内でよりシンプルで標準的です。 Freeswitchの公式Webサイトには、インストールと構成に適したドックがあります。 しかし、テレフォニーサーバーにはWebインターフェイスがないため(私は電話交換のWebインターフェイスの主な相手ですが、これは次回はまったく異なる話です)、無制限の人の限られたサークルが電話帳を設定できます。データ 、 リクエストなど 私の場合のように、 コンソールもです。 なぜMySQLではないのですか? 必要なかったからです。 電話帳にロシアのすべてが含まれているわけではありませんが、連絡先は約500件です。 このため、SQLiteは見えないことが判明しました。 2番目の問題は、情報を追加するプロセスでした。 複数のテーブルに追加し、関係を考慮して、重複を忘れないでください。 電話帳の情報を追加および更新する要求の実行順序に関するドキュメントがまだどこかにあります。 利点は明らかです-データベースエンジンは、追加のソフトウェアのインストールと統合を必要とせず、それ自体はモーニングと同じくらい簡単です。 電話帳全体が1つのファイルにまとめられており、簡単にバックアップして保存できます。 内部のテーブルは非常にシンプルで、構造を理解するのに特別な思考プロセスは必要ありません。
電話帳の2番目のバージョンは実装するのが簡単ではありませんでした。 現在、CMDB iTopをマスターしようと積極的に取り組んでいるので、電話帳を横断するというアイデアが浮上しました。 幸いなことに、CMDBには標準の連絡先ストレージモジュールが存在し、一貫しています。 標準的な方法を使用してこれを行うことはできませんでした。 ルアは救助に来て、彼女のすべてがきれいできれいになった。 このアプローチの利点には、連絡先を追加および編集するための便利なインターフェイスの存在、CMDBにデータを保存し、電話交換機に転送し、コールのルーティング時に使用する機能が含まれます(まだ使用されていませんが計画されています)。 欠点-もちろん、ネットワーク上の伝送遅延、外部サービスへの依存、この経済全体のプログラミングと試運転の必要性。 しかし、結果には価値があります。 ところで、このようなオプションを適用するよう説得するのではなく、その例だけで、外部サービスとのやり取りを整理する方法を示したいと思います。
ケーキ
古いITの伝統によると、単純なものから複雑なものに移行します。 ソファに横たわって先延ばしから始めましょう。 どれだけシンプルかをご覧ください。 しかし、仕事はオオカミではありません、あなたはそれを蹴ることはありません、したがって、私たちは体を垂直位置に移動し、電話交換コンソールに近づけます...
Freeswitchの電話帳モジュールは、古いサイトでは mod_cidlookup Descriptionと呼ばれ、新しいサイトでは Descriptionと呼ばれます 。 最初に、モジュールが一緒にあるかどうかを判断する必要があります。 誰が知っている、突然、いつの間にか漏れた。
modulesフォルダーでモジュールの存在を探します。
ls -la /usr/local/freeswitch/mod/ | grep mod_cidlookup
ファイルがなかった場合、悪いニュースがあります。 モジュールを組み立てるか、再インストールする必要があります。 私は自分でFreeswitchをビルドしたいので、ビルドのソースツリーは常に手元にあります。 Freeswitch用のモジュールを構築する方法の説明はこの記事の範囲を超えているため、そのままにしておき、モジュールが必要なフォルダーに既にあると仮定します。 次に、構成してデータを準備する必要があります。 メインモジュールの構成設定はファイルにあります
/usr/local/freeswitch/conf/autoload_configs/cidlookup.conf.xml
最小作業構成は次のようになります。
作業設定
<configuration name="cidlookup.conf" description="cidlookup Configuration"> <settings> <!-- . --> <param name="cache" value="true"/> <!-- - . --> <param name="cache-expire" value="86400"/> <!-- . 3 (, !) . , , . , . --> <param name="odbc-dsn" value="sqlite:///usr/local/freeswitch/db/phonebook.db"/> <!-- . . . --> <param name="sql" value=" SELECT (name || (CASE WHEN comment != '' THEN ' (' || comment || ')' ELSE '' END)) AS name FROM numbers n JOIN phonebook p ON n.pid = p.id WHERE n.number='${caller_id_number}' LIMIT 1 "/> </settings> </configuration>
SELECTの条件式に注意してください。 データベースおよびコメントフィールドからクライアントの会社を抽出できます。 フィールドが空の場合、期待どおりに姓と名のみが返されます。 常に1行のみが返されるため、重複は無視され、最も早い電話帳エントリが返されます。 したがって、データを追加する前に、それらがデータベースにないことを確認してください。 電話帳バインディングは、1人のユーザーに対して複数の電話番号をサポートするために使用されます。
電話帳用のデータベースを作成しています。
sudo -u freeswitch sqlite3 /usr/local/freeswitch/db/phonebook.db
-- . -- . CREATE TABLE phonebook ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, name VARCHAR (128) NOT NULL, comment VARCHAR (256) ); CREATE INDEX name ON phonebook (name); -- . CREATE TABLE numbers ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, pid INTEGER REFERENCES phonebook (id) ON DELETE CASCADE NOT NULL, NUMBER VARCHAR (32) NOT NULL ); CREATE INDEX NUMBER ON numbers (NUMBER); -- . INSERT INTO `phonebook` (`name`, `comment`) VALUES (' ', ' , '); INSERT INTO `numbers` (`pid`, `number`) VALUES (LAST_INSERT_ROWID(), '79152323245'); INSERT INTO `phonebook` (`name`) VALUES (' '); INSERT INTO `numbers` (`pid`, `number`) VALUES (LAST_INSERT_ROWID(), '74953462323');
SQLiteコンソールを終了します。
.exit
次に、モジュールをダウンロードして、新しく作成した電話帳に設定する必要があります。 Freeswitchコンソールに入ります。
fs_cli
ロード済みの電話帳モジュールを探しています。
freeswitch@internal> show modules mod_cidlookup 0 total.
ええ、モジュールはありません。 ダウンロードしてみてください。
freeswitch@internal> load mod_cidlookup +OK Reloading XML +OK 2016-10-29 14:36:33.890548 [DEBUG] mod_cidlookup.c:122 Connecting to dsn: sqlite:///usr/local/freeswitch/db/phonebook.db 2016-10-29 14:36:33.890548 [INFO] mod_enum.c:880 ENUM Reloaded 2016-10-29 14:36:33.890548 [INFO] switch_time.c:1415 Timezone reloaded 1781 definitions 2016-10-29 14:36:33.890548 [CONSOLE] switch_loadable_module.c:1538 Successfully Loaded [mod_cidlookup] 2016-10-29 14:36:33.890548 [NOTICE] switch_loadable_module.c:292 Adding Application 'cidlookup' 2016-10-29 14:36:33.890548 [NOTICE] switch_loadable_module.c:338 Adding API Function 'cidlookup' .
モジュールがロードされました。 データベースへの接続に問題がある場合は、ログに表示されます。 ロードされたモジュールの中から再び探しています。
freeswitch@internal> show modules mod_cidlookup type,name,ikey,filename api,cidlookup,mod_cidlookup,/usr/local/freeswitch/mod/mod_cidlookup.so application,cidlookup,mod_cidlookup,/usr/local/freeswitch/mod/mod_cidlookup.so 2 total.
次に、モジュールの正常性をテストする必要があります。 これは、cidlookup API関数を使用してコンソールから実行することもできます。 その構文を見ます。
freeswitch@internal> show api cidlookup name,description,syntax,ikey cidlookup,cidlookup API,cidlookup status|number [skipurl] [skipcitystate] [verbose],mod_cidlookup 1 total.
電話帳に追加したデータを思い出して、APIの動作をテストします。
freeswitch@internal> cidlookup 79152323245 ( , ) freeswitch@internal> cidlookup 74953462323
ご覧のとおり、この関数は電話帳から正しい連絡先データを返します。 さらに、コメントがある場合は、括弧で囲まれて返されます。 次に、この機能をダイヤルプランに追加して、人々に光と喜びをもたらす必要があります。 ダイヤルプランはすべての人で異なるように配置されているため、電話帳に関する部分のみを示し、おおよその位置を示します。 /usr/local/freeswitch/conf/dialplan/public.xmlファイルにあります。
<!-- . --> <!-- . --> <extension name="cid_number_cleanup" continue="true"> <condition field="caller_id_number" expression="^(\d+)$"> <action application="set" data="effective_caller_id_number=$1" inline="true"/> </condition> </extension> <!-- . --> <extension name="cid_name_cleanup" continue="true"> <condition field="caller_id_name" expression="^(\d+)$"> <action application="set" data="effective_caller_id_name=$1" inline="true"/> </condition> </extension> <!-- , , , . . --> <extension name="cid_lookup" continue="true"> <condition field="${module_exists(mod_cidlookup)}" expression="true"/> <condition field="caller_id_name" expression="^(\d+)$|^$"/> <condition field="caller_id_number" expression="^(\d+)$"> <action application="cidlookup" data="$1"/> </condition> </extension>
ファイルを保存し、コマンドでダイヤルプランを再起動します
fs_cli -x reloadxml
エラーがなければ、モジュールの動作を確認できます。 十分にプレイしたら、自動ロードするモジュールを追加します。 これは、ファイル/usr/local/freeswitch/conf/autoload_configs/modules.conf.xmlで行われます。 そこに行を探しています
<load module="mod_cidlookup"/>
コメントを外します。 欠落している場合は、ファイルの最後に追加します。
これで、電話帳が設定されました。 しかし、何かを絶えず改善したくない場合、管理者は管理者ではありません。 そして、この道に沿った旅は、私たちの物語の次の部分につながります。
ロックしましょう
FreeswitchとiTopの相互作用は、 公式Webサイトで説明されているRESTインターフェイスを介して、完全に標準的な方法で配置されます。 難しさは何ですか? 彼とは直接連携しないため、プラグイン
- iTopを開き、サイドメニューで、アドレス[ データ管理 ] → [ 組織 ]に移動し、右ボタン[ 新規... ]をクリックします。

- 必須フィールドに入力し、「 作成 」ボタンをクリックします。

- すべてが正しく行われると、作成された組織のページに転送されます。

- ここで、メニューでアドレス構成管理→連絡先→連絡先の作成に移動します 。 開いたウィンドウで、連絡先のタイプ「 Person 」を選択し、「 適用 」をクリックします。

- 連絡先を追加するためのウィンドウが開きます。 必要なすべてのフィールドに入力し、「 作成 」ボタンをクリックします。 標準のiTopインストールでは、追加の電話が含まれるフィールドの一部はないことに注意してください。これらの電話は、いくつかの電話の問題を解決するためにモデルを編集することによって追加されました。 モデルの編集は記事の範囲を超えています;詳細はこちらをご覧ください。

- 連絡先ページにリダイレクトされた場合、すべてが正しく行われています。

同様に、さらにいくつかの連絡先を追加します。 これで、どこに目を向ければよいかがわかり、電話交換の設定に進むことができます。 先ほど言ったように、iTop RESTインターフェースを使用してリクエストします。 彼のリストと思慮深いテイスティングの結果、次のリクエストが出されました。
{ "operation": "core/get", "class": "Person", "key": "SELECT Person AS P WHERE P.phone = '79101001122' OR P.add_phone = '79101001122' OR P.add_phone_2 = '79101001122' OR P.mobile_phone = '79101001122' OR P.add_mobile_phone = '79101001122'", "output_fields": "friendlyname,org_id_friendlyname,function" }
Curlを使用して実行してみましょう。
curl -XPOST 'https://<itop_address>/webservices/rest.php?version=1.0' -d 'auth_user=admin&auth_pwd=password&json_data=%7B%22operation%22%3A%22core%2Fget%22%2C%22class%22%3A%22Person%22%2C%22key%22%3A%22SELECT%20Person%20AS%20P%20WHERE%20P.phone%20%3D%20%2779101001122%27%20OR%20P.add_phone%20%3D%20%2779101001122%27%20OR%20P.add_phone_2%20%3D%20%2779101001122%27%20OR%20P.mobile_phone%20%3D%20%2779101001122%27%20OR%20P.add_mobile_phone%20%3D%20%2779101001122%27%22%2C%22output_fields%22%3A%22friendlyname%2Corg_id_friendlyname%2Cfunction%22%7D'
ご覧のとおり、リクエストには認証が必要です。 iTopのユーザーが存在し、要求を実行するために必要な権限を持っている必要があります。
応答として、ユーザーを見つけます:
{ "objects": { "Person::486": { "code": 0, "message": "", "class": "Person", "key": "486", "fields": { "friendlyname": "\u0412\u0430\u0441\u0438\u043b\u0438\u0439 \u041f\u0443\u043f\u043a\u0435\u0432\u0438\u0447", "org_id_friendlyname": "\u0420\u043e\u0433\u0430 \u0438 \u043a\u043e\u043f\u044b\u0442\u0430", "function": "\u0421\u0443\u043f\u0435\u0440\u0445\u043e\u043c\u044f\u043a" } } }, "code": 0, "message": "Found: 1" }
より読みやすいバージョンで
{ "objects": { "Person::486": { "code": 0, "message": "", "class": "Person", "key": "486", "fields": { "friendlyname": " ", "org_id_friendlyname": " ", "function": "" } } }, "code": 0, "message": "Found: 1" }
そのため、データが送受信され、ユーザーが検索されます。 お気に入りのIDEを見つけて、インスピレーションを与える何かを書く時が来ました。 Freeswitchスクリプト用に別のフォルダーを作成します。
mkdir /usr/local/freeswitch/scripts
このフォルダーに、共有ライブラリーを格納するサブフォルダーlibを作成します。
mkdir /usr/local/freeswitch/scripts/lib
ソケットとSSLを操作するための標準ライブラリが必要になります。
sudo apt-get install lua-socket lua-sec
JSONのエンコードとデコードにも役立つライブラリ。 私はhttp://regex.info/blog/lua/jsonライブラリを選択しました。 それをダウンロードして、適切なフォルダーに配置します。
wget http://regex.info/code/JSON.lua -O lib/json.lua
そして今、私たちのコードがこの世界に入るためのすべての準備が整いました。 scriptsフォルダーにcidlookup.luaファイルを作成し、ハードキーボードで次のコードを追加します。
/usr/local/freeswitch/scripts/cidlookup.lua
-- iTop. local itop_addr = 'https://<itop_address:port>'; local itop_user = 'admin'; local itop_pass = 'password'; -- . local json = (loadfile '/usr/local/freeswitch/scripts/lib/json.lua')(); -- . --[[ . Freeswitch. . . , , . Lua, . -. ]]-- -- local phone = arg[1]; local phone = argv[1]; -- . local command = { operation = 'core/get', class = 'Person', key = 'SELECT Person AS P WHERE P.phone = "' .. phone .. '" OR P.add_phone = "' .. phone .. '" OR P.add_phone_2 = "' .. phone .. '" OR P.mobile_phone = "' .. phone .. '" OR P.add_mobile_phone = "' .. phone .. '"', output_fields = 'friendlyname,org_id_friendlyname,function' }; -- iTop. local http = require 'socket.http'; local https = require 'ssl.https'; local ltn12 = require 'ltn12'; local request = 'auth_user=' .. itop_user .. '&auth_pwd=' .. itop_pass .. '&json_data=' .. json:encode(command); local respbody = {}; -- , , iTop - . -- - , . http.TIMEOUT = 3; local body, code, headers, status = https.request { protocol = 'tlsv1', method = 'POST', url = 'https://' .. itop_addr .. '/webservices/rest.php?version=1.0', source = ltn12.source.string(request), headers = { ["Accept"] = "*/*", ["Accept-Encoding"] = "gzip, deflate", ["Accept-Language"] = "en-us", ["Content-Type"] = "application/x-www-form-urlencoded", ["content-length"] = string.len(request) }, sink = ltn12.sink.table(respbody) }; -- , . caller_id = phone; -- JSON. local response = json:decode(tostring(table.concat(respbody))); -- , - . if(not((response == nil) or (response["objects"] == nil))) then local index = next(response["objects"]); local contact = response.objects[index]["fields"]; -- . caller_id = contact.friendlyname .. "(".. contact.org_id_friendlyname .. (not(contact["function"] == "") and ", " .. contact["function"] or "") .. ")"; end --[[ Freeswitch. . . ]]-- stream:write(caller_id); -- io.write(caller_id .. "\n");
戦いで私たちの創造をテストする時が来ました。 コマンドラインから操作用のスクリプトを編集し、操作性を確認します。
lua cidlookup.lua 79101001122 ( , )
素晴らしい、すべてが正常に機能します。 スクリプトを編集し、コマンドラインからの作業を無効にします。 次に、スクリプトをFreeswitchに接続します。 最初に、適切なモジュールがあることを確認する必要があります。 Freeswitchコンソールに入ります。
fs_cli
Luaモジュールの負荷を確認します。
freeswitch@internal> show modules mod_lua type,name,ikey,filename api,lua,mod_lua,/usr/local/freeswitch/mod/mod_lua.so api,luarun,mod_lua,/usr/local/freeswitch/mod/mod_lua.so application,lua,mod_lua,/usr/local/freeswitch/mod/mod_lua.so dialplan,LUA,mod_lua,/usr/local/freeswitch/mod/mod_lua.so 4 total.
これらの行が表示されている場合、すべてが正常であり、モジュールがロードされています。 そこにない場合、モジュールは組み立てられますが、起動されません。 実行しようとしています。
freeswitch@internal> load mod_lua
Freeswitchが実行するモジュールを見つけることができない場合、それを組み立てて再インストールする必要があります。 この問題が正常に解決され、モジュールがロードされたと想定しています。 スクリプトを実行しようとします。
freeswitch@internal> lua cidlookup.lua 79101001122 ( , )
ご覧のとおり、スクリプトは正常に動作し、受信する必要があるすべてのものが動作します。 それをダイヤルプランに追加することは残っています。 記事の最初の部分のように、どこに置くかは教えませんが、その仕事に責任を負うダイヤルプランの一部を提供します。
<!-- . --> <!-- . --> <extension name="cid_number_cleanup" continue="true"> <condition field="caller_id_number" expression="^(\d+)$"> <action application="set" data="effective_caller_id_number=$1" inline="true"/> </condition> </extension> <!-- . --> <extension name="cid_name_cleanup" continue="true"> <condition field="caller_id_name" expression="^(\d+)$"> <action application="set" data="effective_caller_id_name=$1" inline="true"/> </condition> </extension> <!-- , , . . --> <extension name="cid_lookup" continue="true"> <condition field="${module_exists(mod_lua)}" expression="true"/> <condition field="caller_id_name" expression="^(\d+)$|^$"/> <condition field="caller_id_number" expression="^(\d+)$"> <action application="set" data="effective_caller_id_name=${lua(cidlookup.lua ${caller_id_name})}"/> </condition> </extension>
次のコマンドでダイヤルプランをリロードします
fs_cli -x reloadxml
そして結果を楽しんでください。
面付け
はい、改善および改善できることがわかっています。 mod_curlに関連付けてコードを簡素化することができ、スクリプトを終了して最適化することができますが、それについては議論しません。 完璧に制限はありません。 しかし、どんな道も最初のステップから始まります。この記事が彼の勤勉な仕事に役立つなら、それは無駄に書かれていないことを意味します。 =)それでは、こんにちは。
PS誰かが役に立つといいな。 あなたのコメントを歓迎します。