2017-10-13 5 views
1

Vous ne savez pas comment expliquer cela puisque j'utilise les liaisons QT dans GO alors j'ai collé une mini-version du programme. J'essaie de revenir de la fonction run() un flux en direct à la fenêtre QT .. J'essaie de nombreuses façons ... le dernier avec des canaux (pas avec succès) quel sera le meilleur moyen de transmettre la sortie en temps réel à la fonction main() afin que mon slot QT puisse mettre à jour la fenêtre?Essayer de renvoyer la sortie live/realtime de la commande shell sous forme de données chaîne de la fonction à la fonction principale

paquet principal

import (
     "fmt" 
     //  "github.com/therecipe/qt/core" 
     "bufio" 
     "github.com/therecipe/qt/widgets" 
     "os" 
     "os/exec" 
) 

func run(input string) string { 

     stream := make(chan string) 

     fmt.Printf("You Clicked The Push Button %s\n", input) 

     cmdName := "/usr/bin/nikto" 
     cmdArgs := []string{"-host", input} 

     cmd := exec.Command(cmdName, cmdArgs...) 
     cmdReader, err := cmd.StdoutPipe() 
     if err != nil { 
       fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err) 
       os.Exit(1) 
     } 

     scanner := bufio.NewScanner(cmdReader) 
     go func() { 
       for scanner.Scan() { 
         fmt.Printf("%s\n", scanner.Text()) 
         stream <- scanner.Text() 
         //stream = fmt.Sprintf("%s\n", scanner.Text()) 
       } 
     }() 

     err = cmd.Start() 
     if err != nil { 
       fmt.Fprintln(os.Stderr, "Error starting Cmd", err) 
       os.Exit(1) 
     } 

     err = cmd.Wait() 
     if err != nil { 
       fmt.Fprintln(os.Stderr, "Error waiting for Cmd", err) 
       os.Exit(1) 
     } 

     input = <-stream 
     return string(input) 
     //return go getOutput(scanner) 

} 

func main() { 
     // Create application 
     app := widgets.NewQApplication(len(os.Args), os.Args) 

     // Create main window 
     window := widgets.NewQMainWindow(nil, 0) 
     window.SetWindowTitle("nikto front end") 
     window.SetMinimumSize2(400, 400) 

     // Create layout 

     Layout := widgets.NewQVBoxLayout() 

     TopLayout := widgets.NewQHBoxLayout() 
     //topright := widgets.NewQHBoxLauout() 

     RLayout := widgets.NewQVBoxLayout() 
     LLayout := widgets.NewQVBoxLayout() 

     Layout.AddLayout(TopLayout, 0) 
     Layout.AddLayout(RLayout, 1) 
     Layout.AddLayout(LLayout, 0) 

     //Create main widget 
     mainWidget := widgets.NewQWidget(nil, 0) 
     mainWidget.SetLayout(Layout) 

     // Create left widget 
     LQWidget := widgets.NewQWidget(nil, 0) 
     LQWidget.SetLayout(LLayout) 

     // Create right widget 

     RQWidget := widgets.NewQWidget(nil, 0) 
     RQWidget.SetLayout(RLayout) 

     // Create label 
     urlLabel := widgets.NewQLabel(nil, 0) 
     urlLabel.SetText("Target: ") 
     TopLayout.AddWidget(urlLabel, 0, 0) 

     // Create a line edit 
     input := widgets.NewQLineEdit(nil) 
     input.SetPlaceholderText("Enter target like http://127.0.0.1") 
     TopLayout.AddWidget(input, 0, 0) 

     // Create checkboxes 
     checkBox1 := widgets.NewQCheckBox2("Default", nil) 
     //checkBox1.SetWindowTitle("Check Box") 
     LLayout.AddWidget(checkBox1, 0, 0) 

     checkBox2 := widgets.NewQCheckBox2("SSL mode", nil) 
     //checkBox2.SetWindowTitle("Check Box") 
     LLayout.AddWidget(checkBox2, 0, 0) 

     checkBox3 := widgets.NewQCheckBox2("no 404", nil) 
     //checkBox3.SetWindowTitle("Check Box") 
     LLayout.AddWidget(checkBox3, 0, 0) 

     output := widgets.NewQTextEdit(nil) 
     LLayout.AddWidget(output, 0, 0) 

     // Create a button and add it to the layout 
     button1 := widgets.NewQPushButton2("2. click me", nil) 
     Layout.AddWidget(button1, 0, 0) 

     button1.ConnectClicked(func(checked bool) { 
       output.Append(run(input.Text())) 
     }) 

     // Set main widget as the central widget of the window 
     window.SetCentralWidget(mainWidget) 

     // Show the window 
     window.Show() 

     // Execute app 
     app.Exec() 
} 

Répondre

2

Soit run retourner le canal, puis le lire dans main (et ne pas lire à partir du canal au run):

package main 

import (
    "bufio" 
    "fmt" 
    "os/exec" 
) 

func main() { 
    // ... 

    button1.ConnectClicked(func(checked bool) { 
      stream := run(input.Text()) 
      go func() { 
        for line := range stream { 
          output.Append(line) 
        } 
      }() 
    }) 

    // ... 
} 

func run(host string) <-chan string { 

    var cmd *exec.Cmd 
    cmdReader, err := cmd.StdoutPipe() 
    if err != nil { 
      // ... 
    } 

    scanner := bufio.NewScanner(cmdReader) 
    stream := make(chan string) 

    go func() { 
      defer close(stream) 

      for scanner.Scan() { 
        fmt.Printf("%s\n", scanner.Text()) 
        stream <- scanner.Text() 
      } 
    }() 

    go func() { 
      if err := cmd.Run(); err != nil { 
        // ... 
      } 
    }() 

    return stream 
} 
+0

vous l'homme! fonctionne comme un charme .. J'ai dû commenter votre cmd pointeur et ajouter mon cmd, cmd: = exec.Command (cmdName, cmdArgs ...) et le reste que vous n'avez pas inclus et maintenant il montre .. J'aime GO canaux! Cela m'aide à le pratiquer. – cfernandezlinux

1

Avez-vous besoin de l'appel à run asynchrone (ce qui nécessiterait des canaux et goroutines)? Sinon, vous pouvez simplement utiliser bytes.Buffer pour capturer la sortie et le retour commande (ce qui est ce que notre implémentation actuelle semble être en train de faire):

func run(input string) string { 
    cmdName := "/usr/bin/nikto" 
    cmdArgs := []string{"-host", input} 

    cmd := exec.Command(cmdName, cmdArgs...) 
    var b bytes.Buffer 
    cmd.Stdout = &b 

    err := cmd.Run() 
    if err != nil { 
     log.Fatal(err) 
    } 

    return b.String() 
} 
+0

hey! Merci beaucoup. Pas vraiment, je ne m'occupe pas vraiment de la façon de le faire ... tant que ça fonctionne. J'ai testé cela et ne semble pas fonctionner comme je le souhaite, en gros la commande shell a une sortie stdout constante, à partir de maintenant je ne recevrai que toute la sortie en même temps. Ce dont j'ai besoin, c'est que la sortie apparaisse le widget comme il sort picure une queue -f/var/log/messages seulement que c'est une commande et finit par finir en cours d'exécution et bien sur n'est pas un fichier .. :) comme ca sera facile sur shell avec popen et similaire appels système, problème ici est avec la fonction et le widget. – cfernandezlinux

+0

Je pense qu'il serait préférable d'utiliser qt pour rendre cette fonctionnalité car il s'agit essentiellement d'un comportement d'interface utilisateur. Pour obtenir ce comportement à partir de 'run', vous devrez vous assurer que' output.Append' peut fonctionner avec le flux d'octets, ce que je ne pense pas être le cas. – abhink

+0

hé merci pour votre aide, l'autre suggestion par Peter est exactement ce dont j'avais besoin .. le problème est que le QT go libs je pense qu'il manque toujours le QProcess qui exécute les commandes du système J'ai ouvert un problème quelques jours mais n'avait pas de réponse alors juste allé la route pure aller. https://github.com/therecipe/qt/issues/474 – cfernandezlinux