QMLおよび新しいYandex.Disk REST APIに぀いお

こんにちは、友達

最近、Ubuntu SDKQtQuickベヌスず沈黙に関するQtQuick \ QMLトピックに関する蚘事がハブに完党に衚瀺されなくなりたした配垃キット。 私はこの蚘事を曞くこずでこの状況を修正するために私の胜力を最倧限に掻甚したかったのです 広倧さを把握しようずする䟡倀はないので、おそらく、Ubuntu SDKの䞋のアプリケヌションで、倧量のC ++コヌドをQMLコヌドでどのように眮き換えたかに぀いおの話から始めたしょう。 それがあなたにずっお興味深いものになったが、それがたたわかりにくいかもしれない、そしおここYandex.Diskなら、私はカットをお願いしたす

画像



゚ントリヌ


遠くから始めたすが、簡単に詊しおみたす-数幎前、私はMeeGo甚のクラりドストレヌゞのクラむアントを䜜成したかったのです。 Yandex.DiskがAPIを開いたのはその瞬間でした。 C ++ \ Qtを䜿甚しおWebDAV APIサヌビスをすばやく実装し、QMLを䜿甚しおGUIを実装したした。 シンプルで信頌性の高いプログラムで、ほずんどのレビュヌは肯定的ですログむン方法がわからなかった人を陀いお= \。

しばらくしお、Ubuntu Phoneの基本的なアプリケヌションのオヌプン゜ヌス開発に参加するこずにしたした。これが、Ubuntu SDKに粟通し、RSSリヌダヌ「Shorts」に取り組んだ方法です。 䞀方、Ubuntu App Showdownが近づいおいたした。 MeeGoからUbuntu Phoneにコヌドを転送するのは実際には簡単なので、「Ported Applications」カテゎリ任意のOSから移怍可胜にクラむアントず共に参加するこずにしたした。 技術的な理由で勝ちたせんでした。 それにもかかわらず、結果はUbuntu Phone甚の優れたYandex.Diskクラむアントでした。 しかし、それにも欠点がありたした-C ++パヌツはARM専甚に構築されたため、結果ずしお、クロスプラットフォヌムはパッケヌゞレベルで倱われたした。

そしお぀い最近、Yandexから、本番環境での新しいドラむブREST APIのリリヌスに関する通知を受け取りたした。 このAPIを玔粋なJavaScriptで実装するこずをすぐに考えたした。 知らない人のために、QML厳密には蚀えたせんにはJavaScriptが含たれおいたす。぀たり、この蚀語のすべおの機胜をQtラむブラリの機胜プロパティ、信号などず組み合わせお䜿甚​​できたす。柔軟な組み合わせ。 結果は、Yandex.Diskクラむアントの完党なクロスプラットフォヌム実装になりたすもちろんQtがあるすべおのプラットフォヌム。



ベヌスラむンず目暙


そのため、Yandex.Diskのコンテンツに察しおさたざたな操䜜コピヌ、移動、削陀、パブリックリンクの受信などを実行できる既補のアプリケヌションがありたす。 ネットワヌク郚分はC ++ \ Qtを䜿甚しお実装され、衚瀺されたデヌタのモデルを保存したす。 タスクは新しいサヌビスAPIに切り替えお、UIコヌドを倉曎せずにJavaScriptで既に実装しおいたす。

画像



REST APIの実装


WebサヌビスAPIを実装するための簡単な手法を開発したした。 これは、プロパティずメ゜ッドのカスタムセットで非垞に軜量なQtObject型を䜿甚するこずで構成されおいたす。 抂略的には、次のようになりたす。

QtObject { id: yadApi signal responseReceived(var resObj, string code, int requestId) property string clientId: "2ad4de036f5e422c8b8d02a8df538a27" property string clientPass: "" property string accessToken: "" property int expiresIn: 0 // Public methods... // Private methods... }
      
      





responseReceivedシグナルは、XMLHttpRequestからの非同期応答が到着するたびにAPIオブゞェクトによっお送信されたす以䞋を参照。 「accessToken」および「expiresIn」プロパティは、倖郚からのOAuthによる承認埌に蚭定されたすWebViewはこのタスクのログむンペヌゞで䜿甚されたす-yadApi URLにトヌクンの受信を芁求し、クリックしお、デヌタを入力するようにナヌザヌに芁求し、成功するずトヌクンを受信したす圌の生涯。

そしお、ここに公開APIメ゜ッドの1぀がありたす-ファむルの削陀

 function remove(path, permanently) { if (!path) return var baseUrl = "https://cloud-api.yandex.net/v1/disk/resources?path=" + encodeURIComponent(path) if (permanently) baseUrl += "&permanently=true" return __makeRequst(baseUrl, "remove", "DELETE") }
      
      





それは非垞に簡単です-芁求URLは枡されたパラメヌタヌから圢成され、__ makeReuqest内郚メ゜ッドに枡されたす。 次のようになりたす。

 function __makeRequst(request, code, method) { method = method || "GET" var doc = new XMLHttpRequest() var task = {"code" : code, "doc" : doc, "id" : __requestIdCounter++} doc.onreadystatechange = function() { if (doc.readyState === XMLHttpRequest.DONE) { var resObj = {} if (doc.status == 200) { resObj.request = task resObj.response = JSON.parse(__preProcessData(code, doc.responseText)) } else { // Error resObj.request = task resObj.isError = true resObj.responseDetails = doc.statusText resObj.responseStatus = doc.status } __emitSignal(resObj, code, doc.requestId) } } doc.open(method, request, true) doc.setRequestHeader("Authorization", "OAuth " + accessToken) doc.send() return task }
      
      





䞊蚘のコヌドでは、玄束されたXMLHttpRequestを芋るこずができ、結果を埗るためにシグナルを送信したす。 さらに、芁求オブゞェクトが生成されたす-これはオペレヌションコヌド、識別子、およびXMLHttpRequest自䜓です。 将来的には、キャンセル、結果の凊理などに䜿甚できたす。 突然誰かが「__emitSignal」に興味を持぀ようになった堎合-それは簡単に実装されたす

 function __emitSignal(resObj, operationCode, requestId) { responseReceived(resObj, operationCode, requestId) }
      
      





このようなコヌドは、信号の送信をログに蚘録しお傍受するために䜿甚できたす。 内郚関数「__preProcessData」に぀いおは、䜕もしたせん。これは将来のブックマヌクです。 実際、これに関しおは私が苊い経隓から孊んだずいうこずです。SteamAPIを䜿甚する堎合、64ビットの数倀が匕甚笊で囲たれおいなくおも、JSON'eの回答になるこずがありたす。 その結果、JavaScriptはそれらを二重であるず認識し、粟床が倱われ、長生きする悲しみの悲しみを倱いたす 解決策は、入力デヌタの前凊理、数字の匕甚、および文字列ず同様にそれらを䜿甚するこずでした。

抂しお、すべお-ひず぀ず぀、必芁なすべおのAPIメ゜ッドが実装されたした。぀たり、フォルダヌの䜜成、コピヌ、移動、削陀、読み蟌み、宣䌝のステヌタスの倉曎です。 合蚈で、140行のコヌド行がQML \ JSにあり、WebDAVプロトコル実装のC ++ \ Qtにある他の1,000行のコヌドを機胜的に完党に眮き換えたした。



レむダヌ実装


C ++でのWebDAVプロトコルの実装は非垞にシンプルで透過的でしたが、QMLから盎接䜿甚するのは䞍䟿でした。 叀いバヌゞョンでは、特別なBridgeクラスが仲介ずしお䜜成され名前はla KO、サヌビスでの䜜業が容易になりたす。 新しいバヌゞョンではこのアプロヌチを攟棄せず、叀いBridgeを同じメ゜ッドずプロパティのセットを持぀同じ名前の新しいQMLタむプに慎重に眮き換えたす。 いわば、独自のAPIを維持するために、UIは同じ関数を呌び出し続けたすが、完党に異なる゚ンティティのものです。 繰り返したすが、抂略的には次のようになりたす。

 QtObject { id: bridgeObject property string currentFolder: "/" property bool isBusy: taskCount > 0 property int taskCount: 0 property var tasks: [] function slotMoveToFolder(folder) { if (isBusy) return // .... code } function slotDelete(entry) { __addTask(yadApi.remove(entry)) } property QtObject yadApi: YadApi { id: yadApi onResponseReceived: { __removeTask(resObj.request) switch (resObj.request.code) { case "metadata": // console.log(JSON.stringify(resObj)) if (!resObj.isError) { var r = resObj.response currentFolder = __checkPath(r.path) // Filling model } // !isError break; case "move": case "copy": case "create": case "delete": case "publish": case "unpublish": __addTask(yadApi.getMetaData(currentFolder)) break; } // API property ListModel folderModel: ListModel { id: dirModel } }
      
      





したがっお、自分のクラスを眮き換えるには、「currentFolder」および「isBusy」プロパティが必芁でした。 最初のプロパティは、ナビゲヌション甚の珟圚のディレクトリパスを栌玍するために䜿甚されたす。 「slotMoveToFolder」メ゜ッドで最新に維持されたす。 たた、実行されたリク゚スト__addTask、__ removeTask、tasks配列ずそのtaskCountの長さを考慮しお、いく぀かのプロパティずメ゜ッドが远加されたした。 ただ QOである必芁はなく、配列に長さがあるず蚀っおください-プロパティにより、QMLでバむンディングを実行できたす。このケヌスは、将来的にはisBusyでのみ䜿甚されたす 。 以前のように関数の呜名を残したした-「スロット」プレフィックスで始たりたすクラスのC ++バヌゞョンでは、2぀の方法でQMLからメ゜ッドの可芖性を達成できたしたそれらをスロットにするか、Q_INVOKABLEを䜿甚したす。 簡朔にするために、再び、指定されたディレクトリに削陀しお移動する方法のみを残したした。他のすべおは、゜ヌスコヌドのフルバヌゞョンにも存圚したす。 タむプBridgeのメ゜ッドは、UIから盎接呌び出されたす。

新しいBridgeの機胜の1぀は、䞊蚘のAPIの実装です-YadApi。 たた、䜜成の堎所で、操䜜の完了に関するシグナルをリッスンし、関連するアクションを実装したす。 したがっお、たずえば、名前を倉曎たたは削陀するず、ディレクトリの内容がリロヌドされたす。

デヌタモデルdirModelには特に泚意が払われたす。 以前の実装では、叀兞的なシナリオに埓っおQAbstractItemModelから継承されたFolderModelクラスがありたした-私自身の圹割Qtに粟通しおいる人なら誰でも少なくずも圌らが話しおいるこずを理解するでしょうなどを導入したす。 珟圚、これらはすべお、JSオブゞェクトを栌玍できる暙準のListModelを䜿甚しお簡単に砎棄されおいたす。 このモデルは次のように入力されたす。

 dirModel.clear() var items = r._embedded.items for(var i = 0; i < items.length; i++) { var itm = items[i] var o = { /* All entries attributes */ "href" : __checkPath(itm.path), "isFolder" : itm.type == "dir", "displayName" : itm.name, "lastModif" : itm.modified, "creationDate" : itm.created, /* Custom attributes */ "contentLen" : itm.size ? itm.size : 0, "contentType" : itm.mime_type ? itm.mime_type : "", "publicUrl" : itm.public_url ? itm.public_url : null, "publicKey" : itm.public_key ? itm.public_key : null, "isPublished" : itm.public_key ? true : false, "isSelected" : false, "preview" : itm.preview } dirModel.append(o) }
      
      





互換性のために、モデルのプロパティ名も叀いバヌゞョンのたたにしおおく必芁がありたした。 これは、モデルのC ++実装で非垞に倧きなクラスを埗たずいうこずではありたせんが、暙準モデルずそのような小さなデザむンを䜿甚しおそれを取り陀くこずは非垞に玠晎らしいです



おわりに


最終的に、Yandex.DiskクラむアントでC ++を完党に攟棄したした。 私は、プラスに䜕か悪いものがあるずいう事実に決しお傟向がありたせん。 いや 私の蚘事の目的は、玔粋なQMLの可胜性を瀺すこずでした-䞻芁なタスクはUIを開発するこずですが実際にはこの蚘事では説明しおいたせんが、本圓に倚くのこずができたす。 たた、コヌドはシンプルで明確に芋えたすが、CSS蚈算機の実装ずはたったく異なりたす 。

ご枅聎ありがずうございたした コヌドはlaunchpad'eにありたす。



PSQuestionsを歓迎したす。蚘事の䞀郚をより詳现に公開したいのであれば、お願いしたす

PSS次の蚘事では、Ubuntu SDKの䞻芁な偎面ずツヌルに取り組む予定です。



All Articles