2014年10月5日日曜日

HubotからWinSCPを用いてファイルをFTP(/SFTP/SCP/WebDAV)アップロードしてチャットに告知する関数

Redmineでチケットが更新されたら、その中のfilenameフィールドに記載されたファイルを、所定のサーバへアップロードするというプログラムを作りました。



この関数は、その動作のうち、名前がfilenameのファイルを所定のサーバへアップロードする動作の部分を担うものです。
WinSCP 5.6.1 betaの.NET Assemblyをたたいています。
.NET Assemblyのマニュアルに載ってる作成例を、Hubotのnode.jpのCoffeeScriptへ移植したものです。
関数の引数robotとroomは単に、チャット(ウチはIRC)をコンソール出力として使っています。


#FTP
upload = (robot, room, filename) ->
  robot.messageRoom room, "path=#{filename}"
  try
    win32ole = require('win32ole')
    sessionOptions = win32ole.client.Dispatch 'WinSCP.SessionOptions'
    sessionOptions.Protocol = 2 # Protocol_Sftp = 0, Protocol_Scp = 1, Protocol_Ftp = 2, Protocol_Webdav = 3
    sessionOptions.HostName = "123.456.789.012"
    sessionOptions.UserName = "oreore"
    sessionOptions.Password = "oredayo"
    sessionOptions.FtpMode = 1 # FtpMode_Passive = 0, FtpMode_Active = 1
    session  = win32ole.client.Dispatch 'WinSCP.Session'
    robot.messageRoom room, "セッションオブジェクト作成成功"
    try
      # Connect
      session.Open sessionOptions
      robot.messageRoom room, "セッションオープン成功"

      # Upload files
      transferOptions = win32ole.client.Dispatch 'WinSCP.TransferOptions'
      transferOptions.TransferMode = 0 # TransferMode_Binary = 0, TransferMode_Ascii = 1, TransferMode_Automatic = 2
      robot.messageRoom room, "transferOptions設定成功"

      transferResult = session.PutFiles "D:\\oreore\\#{filename}", "/ore/OREDAYO/", false, transferOptions
      robot.messageRoom room, "ファイルアップロード完了"
       
      # Throw on any error
      transferResult.Check
      robot.messageRoom room, "ファイルアップロードチェック成功"
       
    finally
      # Disconnect, clean up
      session.Dispose
      robot.messageRoom room, "セッション廃棄成功"
  catch e
    robot.messageRoom room, "catch=#{e}"




"..."と'...'の使い方に一貫性がないのは見逃してください ^^;
あくまで、まずは、動くかどうかの試しですので…。

win32oleでタイプライブラリ内のenumを取得する方法がわからない。
その手法が記されると期待されるサンプル「typelibrary_sample.js」がめっちゃ作りかけ。2行しかない。中身ナッシング。
仕方ないのでOLE/COM Object Viewer 2.10.059をどこからともなく入手してインストール。IVIEWERS.DLLもどこからともなく入手。これでenumの数値がわかりますので、数値直書き。

コンピちゃんの中身は全部数字なのよ
うわべにだまされてはだめよ


セッションにファイル転送完了イベントとか転送中(1秒に1回を最小限度とする頻度)イベントがありますので、それにリスナを加えれば、プログレスバーとか進捗ログをリアルタイムにどこかに出して見せることもできるはず。

PutFiles()は非同期じゃないので、叩かれたヤツから直接この関数を呼ぶ作りだと、そいつを待たせてしまう。
なので、そいつは「要転送フラグ」をどこか(Redmineのチケットのフィールドとか)に残したところでいったん終わっておく。
で、あらためてHubotのcron機能でフラグを見つけ、この関数を呼ぶ。
みたいな作りにするほうが適切と思われます。
node.jsの非同期プログラミングまるでわかってないのでそんなことしなくてももしかしてできるのかもしれませんが…。
(2014.10.5 15:49追記)robot.emitとrobot.onでよさげ。

node.jsで使えるFTPモジュール


node.jsにはFTPのモジュールがいっぱいあるのに、なんでわざわざwin32ole経由でWinSCP .NET Assembly経由でWinSCPをたたくなんてまどろっこしいことするんだと思われるかもしれません。

これは、FTPのパッシブ接続でなくアクティブ接続をしたいがためと、WebDAV接続をしたいがためです。

なぜそれらをしたいかというと、アクティブ接続をしたいのは、単に、相手側のサーバの実装上の事情のためです。

WebDAV接続とFTP接続を使い分けたいのは、カンボジアと日本の間の転送速度は、場合によって、この2つをうまく使い分けることによって非常に最大化できるためです。


jsftp

https://github.com/sergi/jsftp
jsftpは、使ってみたが、中のコード見たら、おもいっきしパッシブ接続しかできないようである。


node-ftp

https://github.com/mscdex/node-ftp 
http://stackoverflow.com/questions/18603666/active-ftp-client-for-node-js
Also, node-ftp an jsftp don't seem to support active mode, so I think this will be a nice (though rarely used) addition to npm.
この方によれば、node-ftpもパッシブ接続しかできないようである。


ftp-proxy

https://www.npmjs.org/package/ftp-proxy
NodeJS ftp proxy prepared for active and passive connections with transfer stats plugin and logging module
と言っているが、見ても使い方がさっぱりわからない。


WinSCPと.NET Assemblyのインストール法


マニュアルに載ってますが。


  1. WinSCP 5.6.1 betaをインストール。WebDAV機能ほしいのでこのバージョンにしました。
  2. WinSCPのアプリケーションフォルダ内へ、WinSCP 5.6.1 beta .NET assemblyのWinSCPnet.dllをコピー。


.NET Assemblyを.NETでなくCOMで使いたい場合は、さらに、コマンドプロンプトで、WinSCPのアプリケーションフォルダへ移動し、
%WINDIR%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe WinSCPnet.dll /codebase /tlb
を実行。
すると、.NET assemblyがCOMで使えるように登録される。

win32oleのインストール法


上ではさらっと流してますが、当然こいつが介在しないとHubot(node.js)はOLEとお話できません。
そしてこいつはなんか、こちらでビルドしないといけないブツになっております。
そのため、そのための環境構築を含め、インストールかなり面倒です。

前準備:

  • Microsoft Visual C++ 2010 Expressをインストール(!)。
  • Python 2.7.8をインストール(!!)。Add python.exe to Path: これオンにしなくても下記操作でパイトン(※)にパス通ってくれてるかよくわからんので闇雲にオン

本題:

コマンドプロンプトでmyhubotフォルダへ移動し、
npm install win32ole --save && npm install
すると、白い字と黄色い字でVisual Studioからの警告がたくさん出るが、シカト。
myhubot\node_modules\内にwin32oleがダウンロード・インストールされるとともに、myhubot\package.json内のdependencies内にwin32oleが挿入される。

(※)Thailandがサイランドではなく、Angkor Thomがアンコールソムではなく、Ben Thanhがベンサンじゃない東南アジアに長くいると、これがパイソンとは読めない身体となってしまいます。

0 件のコメント:

コメントを投稿