顯示具有 soap 標籤的文章。 顯示所有文章
顯示具有 soap 標籤的文章。 顯示所有文章

2020年3月17日 星期二

使用 curl 仿 DLNA controller 指令播放影片: DLNA protocol + SOAP protocol

大概去年就拿 DLNA 當做個小題目研究了一下,最近工作又需要,再度翻出來複習一下。使用了別人寫的 python 小工具,非常小巧精美:github.com/cherezov/dlnap

裝置搜尋:

$ python dlnap.py
No compatible devices found.
$ python dlnap.py
Discovered devices:
 [a] Name1 @ 192.168.1.2
 [a] Name2 @ 192.168.1.3


播放影片:

$ python dlnap.py -d Name1 --play http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
No compatible devices found.

$ python dlnap.py -d Name1 --play http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
Name1 @ 192.168.1.2
POST AVTransport/control HTTP/1.1
User-Agent: dlnap.py/0.15
Accept: */*
Content-Type: text/xml; charset="utf-8"
HOST: 192.168.1.2:60099
Content-Length: 558
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
Connection: close

<?xml version="1.0" encoding="utf-8"?>
         <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <s:Body>
               <u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
                  <InstanceID>0</InstanceID><CurrentURIMetaData></CurrentURIMetaData><CurrentURI>http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4</CurrentURI>
               </u:SetAVTransportURI>
            </s:Body>
         </s:Envelope>
POST AVTransport/control HTTP/1.1
User-Agent: dlnap.py/0.15
Accept: */*
Content-Type: text/xml; charset="utf-8"
HOST: 192.168.1.2:60099
Content-Length: 401
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
Connection: close

<?xml version="1.0" encoding="utf-8"?>
         <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <s:Body>
               <u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
                  <InstanceID>0</InstanceID><Speed>1</Speed>
               </u:Play>
            </s:Body>
         </s:Envelope>


可惜的,在測試播放影片時總不太順利,推論應當是兩個指令太快,改用 curl 指令測試就很正常:

1. 先設定影片

$ cat SetAVTransportURI.record
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<CurrentURIMetaData></CurrentURIMetaData>
<CurrentURI>http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4</CurrentURI>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>

$ curl -v -X POST --data @SetAVTransportURI.record  -H 'SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"' -H 'Content-Type: text/xml; charset="utf-8"' http://192.168.1.2:60099/AVTransport/control
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 192.168.1.2:60099...
* TCP_NODELAY set
* Connected to 192.168.1.2 (192.168.1.2) port 60099 (#0)
> POST /AVTransport/control HTTP/1.1
> Host: 192.168.1.2:60099
> User-Agent: curl/7.68.0
> Accept: */*
> SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
> Content-Type: text/xml; charset="utf-8"
> Content-Length: 476
>
* upload completely sent off: 476 out of 476 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< EXT:
< CONTENT-TYPE: text/xml; charset="utf-8"
< SERVER: POSIX, UPnP/1.0, Intel MicroStack/1.0.2777
< Content-Length: 336
<
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">

      </u:SetAVTransportURIResponse>
   </s:Body>
* Connection #0 to host 192.168.1.2 left intact
</s:Envelope>


2. 呼叫播放

$ cat Play.record
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<Speed>1</Speed>
</u:Play>
</s:Body>
</s:Envelope>

$ curl -v -X POST --data @Play.record  -H 'SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"' -H 'Content-Type: text/xml; charset="utf-8"' http://192.168.1.2:60099/AVTransport/control
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 192.168.1.2:60099...
* TCP_NODELAY set
* Connected to 192.168.1.2 (192.168.1.2) port 60099 (#0)
> POST /AVTransport/control HTTP/1.1
> Host: 192.168.1.2:60099
> User-Agent: curl/7.68.0
> Accept: */*
> SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
> Content-Type: text/xml; charset="utf-8"
> Content-Length: 316
>
* upload completely sent off: 316 out of 316 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< EXT:
< CONTENT-TYPE: text/xml; charset="utf-8"
< SERVER: POSIX, UPnP/1.0, Intel MicroStack/1.0.2777
< Content-Length: 310
<
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
   <s:Body>
      <u:PlayResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">

      </u:PlayResponse>
   </s:Body>
* Connection #0 to host 192.168.1.2 left intact
</s:Envelope>

2014年8月22日 星期五

[PHP] 擴充 Mantis SOAP API 、處理 DB Query 心得

前置準備:
  • soap api source code 就擺在 mantis/api/soap 中
  • 記得清掉 SoapServer 跟 SoapClient 的 cache 資料,可以用 ini_set("soap.wsdl_cache_enabled", 0); 或是在 new SoapServer 或 SoapClient 時,指定 'cache_wsdl' => WSDL_CACHE_NONE 資訊
預計新增一個 api 名為 mc_user_group ,需要做的動作:
  • 規劃 mc_user_group 的 input 跟 output 資訊,此例 input 為 username, password,而 output 是 ObjectRefArray,由於都是既定 type ,所以不需額外定義
  • 更新 WSDL 定義,可以從已存在的 mc_enum_access_levels api 來仿照
    • <message name="mc_enum_groupRequest">
      <part name="username" type="xsd:string" />
      <part name="password" type="xsd:string" /></message>
      <message name="mc_enum_groupResponse">
      <part name="return" type="tns:ObjectRefArray" /></message>
    • <operation name="mc_enum_group">
      <documentation>Get the enumeration for group</documentation>
      <input message="tns:mc_enum_groupRequest"/>
      <output message="tns:mc_enum_groupResponse"/>
      </operation>
    • <operation name="mc_enum_group">
      <soap:operation soapAction="http://www.mantisbt.org/bugs/api/soap/mantisconnect.php/mc_enum_group" style="rpc"/>
      <input><soap:body use="encoded" namespace="http://futureware.biz/mantisconnect" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
      <output><soap:body use="encoded" namespace="http://futureware.biz/mantisconnect" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
      </operation>
  • 實作 function mc_enum_group( $p_username, $p_password ),若此 function 定義在其他檔案內,記得要更新 mantis/api/soap/mc_core.php 即可
如此一來,就完成擴充 Mantis SOAP api 的任務了,記得要把 Server 跟 Client 的 SOAP Cache 都必須清掉才會正常,不然 client site 會看到類似的訊息(扣除還沒實作的情況):

PHP Fatal error:  Uncaught SoapFault exception: [SOAP-ENV:Server] Procedure 'your_func' not present

以下是片段程式碼:

// Client
$TARGET_API='https://host/mantis/api/soap/mantisconnect.php?wsdl';
ini_set("soap.wsdl_cache_enabled","0");
$c = new SoapClient($TARGET_API);

// debug
// print_r($c->__getFunctions ());

print_r( $c->mc_enum_group($user, $pass) );


// Server
        require_once( 'mc_core.php' );
        ini_set("soap.wsdl_cache_enabled","0");
        $server = new SoapServer("mantisconnect.wsdl",
                        array('features' => SOAP_USE_XSI_ARRAY_TYPE + SOAP_SINGLE_ELEMENT_ARRAYS)
        );
        $server->addFunction(SOAP_FUNCTIONS_ALL);
        $server->handle();


其他心得:

  • 自定 Mantis SOAP API 時,需要留意 input, output 的地方,假設 output 的是 ObjectRefArray 形態,那輸出只能有 id, name ,其他欄位都會被濾掉
  • Mantis SOAP API 使用上要留意權限問題,例如發 issue 用的帳號,若是 repoter 的等級,不能去做 assign monitors 的行為,會有權限問題,有問題時,可以試著用 mc_issue_add 跟 mc_issue_update 交叉測試。

最後,再補一個 DB 操作方式,output 仍以 ObjectRefArray 為例:

function mc_enum_group( $p_username, $p_password ) {
        $t_user_id = mci_check_login( $p_username, $p_password );
        if ( $t_user_id === false ) {
                return mci_soap_fault_login_failed();
        }
         
        $t_result = array();
         
        $query = "SELECT * FROM mantis_user_table";
     
        $result = db_query( $query );
        //file_put_contents('/tmp/debug', print_r($result, true) );

// 此例把 username 充當回傳的 name 資訊、user id 當作回傳 id 資訊
        for( $i=0, $cnt=db_num_rows($result) ; $i<$cnt; ++$i ) {
                $row = db_fetch_array( $result );
                $obj = new stdClass();
                $obj->id = $row['id'];
                $obj->name = $row['username'];
                array_push( $t_result, $obj );
        }    
        return $t_result;
}

2014年8月14日 星期四

[PHP] 使用 Mantis SOAP API - 新增 issue custom_fields

架好 Mantis 後,預設是有開啟 SOAP API 的,可以瀏覽 http://server_ip/mantis/api/soap/mantisconnect.php?wsdl 試試,應該會看到 SOAP API 的使用列表跟使用方式。

對於 custom_fields 的用法,可用在新增一些額外的資料屬性來記錄,必須先新增 custom_fields:

Manage -> Manage Custom Fields -> 填寫想的欄位名字 -> New Custom Field -> 在 Write Access 請填寫 Reporter 以及 Display 的區域也勾一勾 -> update custom field,別忘了下方也要選擇使用的 project 並點選 Link Custom Field

接著,在使用 Mantis SOAP API 時,必須先用 mc_project_get_custom_fields 把 custom_fields 的資料撈出來,因為在使用 mc_issue_add 時,對於 custom_fields 必須填寫 id 跟 name:

// 使用 Hash 來記錄
$custom_fields = array();
foreach( $c->mc_project_get_custom_fields($user, $pass, $project_id) as $raw )
        if (isset($raw->field->name) )
                $custom_fields[$raw->field->name] = $raw->field;


最後再新增 issue data 時,記得 custom_fields 是一個 Array of Object,所以新增的額外欄位資料,請用:

$field_item = new stdClass();
$field_item->field = $custom_fields["Custom_field_name"];
$field_item->value = $custom_fields_value["Custom_field_name"];


例如:

$issue_data = array(
        'project' => array(
                        'id' => $project_id
                ),
        'category' => $issus_category,
        'summary' => $issue_summary,
        'description' => $issue_description,
'custom_fields' => array()
);

$field_item = new stdClass();
$field_item->field = $custom_fields["Custom_field_name"];
$field_item->value = $custom_fields_value["Custom_field_name"];

array_push( $issue_data['custom_fields'] , $field_item );

$issus_id = $c->mc_issue_add($user, $pass, $issue_data);

2014年8月12日 星期二

[PHP] 使用 Mantis SOAP API - Automatically Create an Issue



架好 Mantis 後,預設是有開啟 SOAP API 的,可以瀏覽 /mantis/api/soap/mantisconnect.php?wsdl 試試,應該會看到 SOAP API 的使用列表跟使用方式。

使用上需要指定 user, password 跟 project id,目前沒找到一口氣列出所有 project 的方法?倒是可以用 project name 找 project id,而發一則 issue 必須要有的資訊:project id, category, summary, description,連續動作:

<?php
$c = new SoapClient('http://YourMantisServerIP/mantis/api/soap/mantisconnect.php?wsdl');

$user = 'report_account';
$pass = 'report_password';
$project_name = 'ProjectName';

$issue_summary = 'Report title';
$issue_description = 'Report body';
$issus_category = 'iOS';

$project_id = $c->mc_project_get_id_from_name($user, $pass, $project_name);
if ($project_id == 0) {
        echo "[ERROR] Project ID Not Found: [$project_name]\n";
        exit;
}

$categories = $c->mc_project_get_categories($user, $pass, $project_id);
print_r($categories);

//$custom_fields = $c->mc_project_get_custom_fields($user, $pass, $project_id);
//print_r($custom_fields);

$issue_data = array(
        'project' => array(
                        'id' => $project_id
                ),
        'category' => $issus_category,
        'summary' => $issue_summary,
        'description' => $issue_description
);

$issus_id = $c->mc_issue_add($user, $pass, $issue_data);

echo "Issue ID: $issus_id\n";


成功的話,就會看到最後印出的 Issue ID。

對於 SOAP 的簡介可以參考:如何透過PHP、SOAP 及 WSDL撰寫Web Service