2016-11-16 3 views
0

У меня есть служба angular2, и я хочу, чтобы это сделать следующее:Как сделать эту функцию углового2 несколько синхронной?

  1. Ftp на удаленный сервер
  2. Найдите файл прочитать несколько строк из него
  3. Построить объект JSon «Результаты» и вернуться к вызывающий компонент

Так что, на самом деле у меня есть шаги 1/2, но, конечно же, все его «асинхронные». Так что же происходит в моем компоненте я делаю этот призыв к службе, где this.ftp является экземпляром моей службы:

this.servers = this.ftp.lookForServers(); 

Теперь это правильно вызывает метод lookForServers моего FTP сервиса, который выглядит следующим образом:

lookForServers(){ 
    var servers = []; 
    var whereAreWe = 0; 
    var possibles = ["/path/to/servers/"]; 
    for(var i=0;i<possibles.length;i++){ 
     whereAreWe = i; 
     this.c.list(possibles[i],false,(err,list)=>{ 
     for(var p=0;p<list.length;p++){ 
      console.log(list[p]); 
      var server_version = this.grabLog(possibles[whereAreWe]+list[p].name); 
      servers.push({ 
      name: list[p].name, 
      path: possibles[whereAreWe]+list[p].name, 
      version: server_version 
      }); 
     } 
     }); 
    } 
    return servers; 
    } 

Теперь - вызов this.grabLog(possibles[whereAreWe]+list[p].name); функция заканчивает делать дополнительные звонки в this.c - клиент FTP, который, конечно, является асинхронной, поэтому этот метод возвращает почти сразу - в то время как обратные вызовы продолжают работать. Эти обратные вызовы загружают файл, а затем другая функция обратного вызова обрабатывает этот файл - снова по очереди, асинхронно выбирая различные детали, которые я хочу сохранить.

К концу этой цепи - У меня есть все мои данные в финале:

lineReader.on('close',() => { function - but of course my `this.ftp.lookForServers();` function call has long gone....and the component is none the wiser. 

Так как я могу позволить эту работу асинхронно, и по-прежнему передавать обратно к компоненту моих результатов объект JSON, как только работа завершена? Вероятно, это довольно простой вопрос о том, как сделать вызов службы обратным вызовом компонента ...?

ответ

2

Вам не нужно, чтобы он работал синхронно. Вы должны сделать lookForServers (и другие функции он использует) использовать наблюдаемыми, а затем подписаться на результат, как это:

this.ftp.lookForServers().subscribe((data) => { this.servers = data }); 

Вот реализации:

const Client = require('ftp'); 
const fs = require('fs'); 
const readline = require('readline'); 

import { NextObserver } from 'rxjs/Observer'; 
import { Observable } from 'rxjs/Rx'; 

interface server { 
    name: string; 
    path: string; 
    version: string; 
    java_version: string; 
} 

export class FTPClient { 
    username: string; 
    password: string; 
    host: string; 
    port: number; 
    c: any; 

    constructor() { 
    } 

    init(username, password, host, port) { 
     console.log("initiating FTP connection to:" + host + "on port:" + port); 

     this.username = username; 
     this.password = password; 
     this.host = host; 
     this.port = port; 
     this.c = new Client(); 

     console.log("Client created"); 
    } 

    connect() { 
     console.log("About to start connection"); 

     this.c.on('ready',() => { 
      this.c.list((err: any, list: any) => { 
       if (err) throw err; 

       console.dir(list); 
       this.c.end(); 
      }); 
     }); 

     // connect to localhost:21 as anonymous 
     var connectProps = { 
      host : this.host, 
      port : this.port, 
      user : this.username, 
      password : this.password 
     }; 

     console.log("Connecting now..."); 
     this.c.connect(connectProps); 
    } 

    public lookForServers(name: string): Observable<any[]> { 
     return Observable.create((observer: NextObserver <any[]>) => { 
      let servers = []; 
      let whereAreWe = 0; 
      let possibles = [ "/path/to/servers/" ]; 

      for (var i = 0; i < possibles.length; i++) { 
       whereAreWe = i; 

       this.c.list(possibles[ i ], false, (err: any, list: any) => { 
        for (var p = 0; p < list.length; p++) { 
         this.grabMessagesLog(possibles[ whereAreWe ] + list[ p ].name) 
         .subscribe((data: any) => { 
           let server_version = data; 

           servers.push({ 
            name : list[ p ].name, 
            path : possibles[ whereAreWe ] + list[ p ].name, 
            version : server_version 
           }); 

           observer.next(servers); 
           observer.complete(); 
          } 
         ); 
        } 
       }); 
      } 
     }); 
    } 

    grabMessagesLog(path): Observable<any> { 
     return Observable.create((observer: NextObserver <any>) => { 
      let result = ''; 
      let unix = Math.round(+new Date()/1000); 
      this.c.binary(function(err) { 
       console.log(err); 
      }); 

      this.c.get(path + "/logs/messages.log", (err, stream) => { 
       if (err) throw err; 

       stream.once('close',() => { 
        this.c.end(); 
        this.getServerMetadataFromMessagesLog(unix + "_messages.log") 
        .subscribe((data) => { 
         stream.pipe(fs.createWriteStream(unix + "_messages.log")); 

         observer.next(data); 
         observer.complete(); 
        }); 
       }); 
      }); 
     }); 
    } 

    getServerMetadataFromMessagesLog(path): Observable<any> { 
     return Observable.create((observer: NextObserver <any>) => { 
      let lineReader = readline.createInterface({ 
       input : fs.createReadStream(path) 
      }); 

      let server_version = ""; 
      let java_version = ""; 
      let line_no = 0; 

      lineReader.on('line', function(line) { 
       line_no++; 
       console.log("line number is:" + line_no); 

       if (line.includes("STUFF") && line.includes("FLAG2") && line_no == 2) { 
        var first = line.split("FLAG2")[ 1 ]; 
        var last = first.split(" (")[ 0 ]; 
        var version = "FLAG2" + last; 
        this.server_version = version; 
        console.log("version is:" + version); 
       } 

       if (line.includes("java.version =")) { 
        var javav = line.split("java.version =")[ 1 ]; 
        this.java_version = javav; 
        lineReader.close(); 
       } 

       console.log('Line from file:', line); 
      }); 

      lineReader.on('close',() => { 
       var res = { 
        version : server_version, 
        java_version : java_version 
       }; 

       alert("RES IS:" + JSON.stringify(res)); 

       observer.next(res); 
       observer.complete(); 
      }); 
     }); 
    } 
} 
+0

Хорошо, когда всякий раз, когда вы подписываетесь, все, что вы возвращаете из другого обратного вызова, возвращается обратно в подписанный обратный вызов? – RenegadeAndy

+0

Да. Когда вы делаете .subscribe ((данные), «данные» являются «any []», потому что функция возвращает Observable . –

+0

где я импортирую Observable и NextObserver из? – RenegadeAndy

1

Попробуйте использовать рекурсивный функцию с $timeout функцией углового

function recursiveWait(server_version){ 

    if(server_version != null){ 
     return; 
    } 

    $timeout(function(){recursiveWait()}, 500); 
} 

И разместить его здесь:

 console.log(list[p]); 
     var server_version = this.grabLog(possibles[whereAreWe]+list[p].name); 
     recursiveWait(server_version); 
     servers.push({ 
     name: list[p].name, 

Это спросит вар, если это != null Если оно равно он будет вызывать функция снова в 500 мс, если она не вернется и не выйдет из функции, дайте код продолжить.

+0

кроме server_version будет * всегда * быть нулевым, как функция this.grabLog возвращается почти сразу, так как остальная часть этого кода запускает async ... поэтому я предполагаю, что хочу проверить какую-то переменную, в которой каждый из обратных вызовов имеет контекст, и дождаться этого до! = null ? Также я думаю, что вызов функции timeout должен быть «recursiveWait - not recursiveF»? – RenegadeAndy

+0

server_version будет в какой-то момент! = Чем null. Таким образом, рекурсивная функция будет ждать этого изменения. Функция Async сделает ** тайм-аут ** в js и принудительно возвращает null. Но код продолжает работать, и когда закончите, верните значение. – driconmax

+0

Моя забота заключается в том, что это одна попытка после 500 мс другой, и все это основано на времени, что очень хорошо может привести к сбою на основе скорости процессора и сети. Я знаю, что могу увеличить этот тайм-аут, но все же кажется несколько «шатким» в качестве решения? Есть ли альтернативные подходы? – RenegadeAndy

Смежные вопросы