Transparente Durchreiche zur Konsole?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Slalomsk8er hat geschrieben:Das Ganze sollte eine CGI-HTML-Seite werden mit einem Konsolenfenster und soll sich identisch verhalten, wie die Konsole im Hintergrund (auch ncurses soll 1 zu 1 rüberkommen).
Wie sieht es denn bei dir aus? Stand der Dinge meine ich... Kann man es schon sehen :D
Slalomsk8er
User
Beiträge: 25
Registriert: Samstag 22. Januar 2005, 19:43

Nö leider nicht.

Ich habe mich mal wider einerm anderen Projekt zugewendet Bunnyfight (ich bin der main 3D Artist).

Pexpect experimente waren das Letzte, was ich gemacht hatte (bin mir nicht sicher ob das das Richtige ist). Ach ja, einen Hilferuf an die Pythonnewsgroup hatte ich auch gestartet, jedoch keine Hilfreichen Antworten erhalten.

Gruss, Dominik
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hab mir schon geadcht, dass es scheitert. Ist halt ein sehr komplexes Thema.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Slalomsk8er
User
Beiträge: 25
Registriert: Samstag 22. Januar 2005, 19:43

Gescheitert ist da noch gar nichts.

Das ist so meine Art Dinge zu Erledigen.

Multitasking hält den Frustfaktor gering, da ich dann halt an einem anderen Projekt weiter arbeite und so nach ca. einer Woche weiter knoble (falls ich überhaupt solange die Finger von lassen kann).

Das GMC-Projekt ist schon ein Jahr alt und falls keiner das gleiche vor mir baut, werde ich weiter arbeiten.

Gruss, Dominik
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Na dann ist ja cool. Halt uns doch auf dem laufenden :)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also ich bin mit meiner Variante schon mal ein wenig weiter, nach dem ich den Server mit Python selber mache und diesen so modifiziere, das kein fork verwendet wird. Somit werden Skripte mit dem User ausgeführt, mit dem der Server gestartet wurde:
http://python.sandtner.org/viewtopic.php?p=16132#16132

Und hier eine erste Version einer "console":

Code: Alles auswählen

#!/usr/bin/python

import os, sys, locale

print "Content-type: text/html\n\n"

html='''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<title>console @ %(uname)s</title>
</head>
<body>
<form name="form1" id="form1" method="post" action="%(self)s">
  <p><textarea name="stdout" cols="100" rows="30" id="stdout">%(stdout)s</textarea></p>
  <p><input name="cls" type="checkbox" id="cls" />cls</p>
  <p><input name="cmd" type="text" id="cmd" size="150" /></p>
</form>
</body>
</html>'''




def GetCGIdaten():
    "CGI POST und GET Daten zur einfacheren Verarbeitung zusammen in ein Dict packen"
    CGIdaten={}
    if os.environ.has_key('QUERY_STRING'):
        # POST URL-Parameter parsen
        for i in os.environ['QUERY_STRING'].split("&"):
            i=i.split("=")
            if len(i)==1:
                if i[0]!="":
                    CGIdaten[ i[0] ] = ""
            else:
                CGIdaten[ i[0] ] = i[1]

    from cgi import FieldStorage
    FieldStorageData = FieldStorage()
    # GET Daten auswerten
    for i in FieldStorageData.keys():
        CGIdaten[i]=FieldStorageData.getvalue(i)

    return CGIdaten

CGIdaten = GetCGIdaten()


txt = ""

if CGIdaten.has_key("stdout") and not CGIdaten.has_key("cls"):
    # Alte Ausgaben wieder anzeigen
    txt = CGIdaten["stdout"]

# "Prompt" hinzufügen
txt += os.getcwd()+"> "

if CGIdaten.has_key("cmd"):
    # Befehl ausfühen
    Befehl = CGIdaten["cmd"]
    txt += Befehl+"\n"
    txt += os.popen( Befehl ).read()

print html % {
    "charset"   : locale.getdefaultlocale()[1],
    "uname"     : os.popen("uname -a").read(),
    "self"      : os.environ['SCRIPT_NAME'],
    "stdout"    : txt
    }
Nun könnte ich mal probieren statt os.popen() vielleicht das neue subprocess() zu nutzen, aber so klappt das auch erstmal... Ein nachteil von popen(), es werden stderr ignoriert, aber das ist bei subprocess() ja anders...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Nun könnte ich mal probieren statt os.popen() vielleicht das neue subprocess() zu nutzen, aber so klappt das auch erstmal... Ein nachteil von popen(), es werden stderr ignoriert, aber das ist bei subprocess() ja anders...
Das Modul popen2 kann das auch. Aber subprocess ist natürlich viel lustiger.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Jetzt hab ich's mit subprocess:

Code: Alles auswählen

#!/usr/bin/python

import cgitb ; cgitb.enable()
import os, sys, locale, subprocess

print "Content-type: text/html\n\n"

html='''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<title>console @ %(uname)s</title>
</head>
<body>
<form name="form1" id="form1" method="post" action="%(self)s">
  <p><textarea name="stdout" cols="100" rows="30" id="stdout">%(stdout)s</textarea></p>
  <p><input name="cls" type="checkbox" id="cls" />cls</p>
  <p><input name="cmd" type="text" id="cmd" size="150" /></p>
</form>
</body>
</html>'''




def GetCGIdaten():
    "CGI POST und GET Daten zur einfacheren Verarbeitung zusammen in ein Dict packen"
    CGIdaten={}
    if os.environ.has_key('QUERY_STRING'):
        # POST URL-Parameter parsen
        for i in os.environ['QUERY_STRING'].split("&"):
            i=i.split("=")
            if len(i)==1:
                if i[0]!="":
                    CGIdaten[ i[0] ] = ""
            else:
                CGIdaten[ i[0] ] = i[1]

    from cgi import FieldStorage
    FieldStorageData = FieldStorage()
    # GET Daten auswerten
    for i in FieldStorageData.keys():
        CGIdaten[i]=FieldStorageData.getvalue(i)

    return CGIdaten

CGIdaten = GetCGIdaten()



def cmd( command ):
    process = subprocess.Popen( command,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    return process.stdout.read() + process.stderr.read()


txt = ""

Netzwerknamen = cmd( "uname -n" )

if CGIdaten.has_key("stdout") and not CGIdaten.has_key("cls"):
    # Alte Ausgaben wieder anzeigen
    txt = CGIdaten["stdout"]

# "Prompt" hinzufügen
txt += os.getcwd()+"> "

if CGIdaten.has_key("cmd"):
    # command ausfühen
    command = CGIdaten["cmd"]
    txt += command+"\n"
    txt += cmd( command )

print html % {
    "charset"   : locale.getdefaultlocale()[1],
    "uname"     : cmd("uname -a"),
    "self"      : os.environ['SCRIPT_NAME'],
    "stdout"    : txt
    }
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Nun so nebenbei: da wo du Post und Get parst... kann es ein das du die falsch beschriftet hast? GET ist doch das mit '&' und POST ist doch das was nicht in der URL vorkommt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das kann ich auch nie Auseinander halten, aber lauf selfhtml http://de.selfhtml.org/cgiperl/intro/fo ... m#get_post stimmt das so, wie ich es kommentiert hab... oder sehe ich da was falsch?!?
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Hi Jens,

Code: Alles auswählen

def GetCGIdaten():
    "CGI POST und GET Daten zur einfacheren Verarbeitung zusammen in ein Dict packen"
    CGIdaten={}
    if os.environ.has_key('QUERY_STRING'):
        # GET URL-Parameter parsen
        for i in os.environ['QUERY_STRING'].split("&"):
            i=i.split("=")
            if len(i)==1:
                if i[0]!="":
                    CGIdaten[ i[0] ] = ""
            else:
                CGIdaten[ i[0] ] = i[1]

    from cgi import FieldStorage
    FieldStorageData = FieldStorage()
    # POST Daten auswerten <---------------------
    for i in FieldStorageData.keys():
        CGIdaten[i]=FieldStorageData.getvalue(i)

    return CGIdaten 
MfG
Andreas
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jens hat geschrieben:Das kann ich auch nie Auseinander halten, aber lauf selfhtml http://de.selfhtml.org/cgiperl/intro/fo ... m#get_post stimmt das so, wie ich es kommentiert hab... oder sehe ich da was falsch?!?
Nein, laut diesem Dokument ist das genau andersrum. Aber soo wichtig ist das nun auch nicht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

OK, ihr habt recht :oops:

Ich hab eine neue Version fertig... Damit kann man Fast wie mit Putty arbeiten 8) Naja, zimindest ist es durch ein wenig JavaScript leichter immer wieder ein neues Kommando ein zu geben, denn per JavaScript wird der Fokus auf das Eingabefeld gesetzt... Außerdem geschied die Ausgabe nun als normales HTML... Somit ist der Prompt nun per <strong> Formatiert und alles ist leichter "lesbar"...

Code: Alles auswählen

#!/usr/bin/python

__version__ = "0.0.3"

import cgitb ; cgitb.enable()
import os, sys, locale, subprocess

print "Content-type: text/html\n\n"

html='''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<title>console @ %(uname)s</title>
<script type="text/javascript">
function setFocus() {
    document.form.cmd.focus();
}
</script>
<style type="text/css">
#cmd {
   background-color:#FFEEEE;
}
#cmd:focus {
   background-color:#EEFFEE;
}
</style>
</head>
<body onLoad="setFocus();">
    %(stdout)s
<form name="form" id="form" method="post" action="%(self)s">
    <input type="hidden" name="stdout" value="%(stdout_raw)s">
    <input type="hidden" name="current_dir" value="%(current_dir)s">
    <p><input name="cmd" type="text" id="cmd" size="150" /></p>
</form>
</body>
</html>'''



def GetCGIdata():
    "CGI POST und GET Daten zur einfacheren Verarbeitung zusammen in ein Dict packen"
    CGIdata={}
    if os.environ.has_key('QUERY_STRING'):
        # GET URL-Parameter parsen
        for i in os.environ['QUERY_STRING'].split("&"):
            i=i.split("=")
            if len(i)==1:
                if i[0]!="":
                    CGIdata[ i[0] ] = ""
            else:
                CGIdata[ i[0] ] = i[1]

    from cgi import FieldStorage
    FieldStorageData = FieldStorage()
    # POST Daten auswerten
    for i in FieldStorageData.keys():
        CGIdata[i]=FieldStorageData.getvalue(i)

    return CGIdata

CGIdata = GetCGIdata()



def cmd( command ):
    process = subprocess.Popen( command,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    return process.stdout.read() + process.stderr.read()


if CGIdata.has_key("stdout"):
    # Alte Ausgaben wieder anzeigen
    txt = CGIdata["stdout"]
else:
    txt = ""


if CGIdata.has_key("current_dir"):
    # Ins alte Verzeichnis wechseln
    os.chdir( CGIdata["current_dir"] )

if CGIdata.has_key("cmd"):  # Es wurde ein Befehl eingegeben
    command = CGIdata["cmd"]
    # Eingabe an altem Prompt anhängen
    txt += command+"<br>"
    # Eingegebener Befehl ausführen und Ausgaben anhängen
    txt += cmd( command )

current_dir = os.getcwd()
# Neues, aktuelles Prompt anhängen
txt += "<strong>%s</strong>>" % current_dir

print html % {
    "charset"       : locale.getdefaultlocale()[1],
    "uname"         : cmd("uname -a"),
    "self"          : os.environ['SCRIPT_NAME'],
    "stdout"        : txt.replace("\n","<br>"),
    "stdout_raw"    : txt,
    "current_dir"   : current_dir
    }
Ein Problem bereitet mir aber noch die Handhabung von Verzeichnis-Wechseln...
Wenn per subprocess ein "cd \" ausgeführt wird, ist danach per os.getcwd() ermitteltes Verzeichnis immer noch das Verzeichnis in dem die Python-Datei gestartet wurde...
Somit ist ein umher wandern im Dateisystem noch nicht möglich :(

Ich hab mir zwei Lösungen überlegt... Ich untersuche den eingegebenen Befehl, ob es ein "cd" oder "chdir" ist... Wenn ja, wird der nicht wirklich ausgeführt, sondern nur die Variable "current_dir" angepasst... Der nächste Befehl wird dann im richtigen Verzeichnis ausgeführt...

Oder Aber ich erweitere jeden Befehl mit "; pwd" um das aktuelle Verzeichnis anzeigen zu lassen... Diese Anzeige Filtere ich raus und setzte damit die Variable "current_dir", für`s nächte mal...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab die unelegante "pwd"-Variante genomen...
Außerdem hab ich noch ein wenig rumgespielt:

Code: Alles auswählen

#!/usr/bin/python

__version__ = "0.0.4"

import os, sys, locale, subprocess, re
import xml.sax.saxutils, base64, bz2

maxHistoryLines = 1000

html='''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=%(charset)s" />
<title>console @ %(uname)s</title>
<script type="text/javascript">
function setFocus() {
    document.form.cmd.focus();
    window.scrollBy(0,30);
}
</script>
<style type="text/css">
#cmd {
   background-color:#FFEEEE;
}
#cmd:focus {
   background-color:#EEFFEE;
}
body {
    background-color: #CCCCCC;
    padding: 20px;
    padding-bottom: 50px;
    margin: 10px;
}
html {
    background-color: #FFFFFF;
    margin: 10px;
}
</style>
</head>
<body onLoad="setFocus();">
    %(stdout)s
<form name="form" id="form" method="post" action="%(self)s">
    <input type="hidden" name="stdout" value="%(stdout_raw)s">
    <input type="hidden" name="current_dir" value="%(current_dir)s">
    <p><input name="cmd" type="text" id="cmd" size="150" /></p>
</form>
</body>
</html>'''


def putHTML( HTMLdata ):
    print "Content-Type: text/html"
    if os.environ.has_key('HTTP_ACCEPT_ENCODING'):
        modes = os.environ['HTTP_ACCEPT_ENCODING'].split(',')

        if "gzip" in modes:
            from gzip import GzipFile

            print 'Content-Encoding: gzip\n'
            oldstdout = sys.stdout
            sys.stdout = GzipFile(mode='wb', fileobj=sys.stdout)
            print HTMLdata
            sys.stdout = oldstdout
            return
        elif "deflate" in modes:
            from zlib import compress

            print "Content-Encoding: deflate\n"
            print compress( HTMLdata )
            return
    # Encoding Mode nicht gzip/deflate oder Environ-Variable nicht gesetzt.
    print
    print HTMLdata


def compress( txt ):
    txt = bz2.compress( txt, 9 )
    return base64.urlsafe_b64encode( txt ).replace("\n","")

def decompress( txt ):
    txt = base64.urlsafe_b64decode( txt )
    return bz2.decompress( txt )

def cutLines( txt, maxLines ):
    return '\n'.join( txt.splitlines()[-maxLines:] )

def GetCGIdata():
    "CGI POST und GET Daten zur einfacheren Verarbeitung zusammen in ein Dict packen"
    CGIdata={}
    if os.environ.has_key('QUERY_STRING'):
        # GET URL-Parameter parsen
        for i in os.environ['QUERY_STRING'].split("&"):
            i=i.split("=")
            if len(i)==1:
                if i[0]!="":
                    CGIdata[ i[0] ] = ""
            else:
                CGIdata[ i[0] ] = i[1]

    from cgi import FieldStorage
    FieldStorageData = FieldStorage()
    # POST Daten auswerten
    for i in FieldStorageData.keys():
        CGIdata[i]=FieldStorageData.getvalue(i)

    return CGIdata


def escape( txt ):
    # Evtl. vorhandene Escape Sequenzen rausfiltern
    txt = re.sub(r"\033\[.*?m","",txt)
    # Für Anzeige im Browser escapen
    txt = xml.sax.saxutils.escape( txt )
    return txt


def cmd( command ):
    process = subprocess.Popen( command,
        shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)

    out = process.stdout.read()
    err = process.stderr.read()

    out = escape( out )
    err = escape( err )
    return out, err





CGIdata = GetCGIdata()



if CGIdata.has_key("stdout"):
    # Alte Ausgaben wieder anzeigen
    txt = CGIdata["stdout"]
    compressLen = len( txt )
    # Ausgaben dekomprimieren
    txt = decompress( txt )
    decompressLen = len( txt )
else:
    compressLen = 0
    decompressLen = 0
    txt = ""


## Alte Verzeichnis wieder herstellen
if CGIdata.has_key("current_dir"):
    current_dir = CGIdata["current_dir"]
    if os.path.isdir( current_dir ):
        # Ins alte Verzeichnis wechseln
        os.chdir( current_dir )
    else:
        current_dir = os.getcwd()
else:
    current_dir = os.getcwd()

## Befehl Ausführen
if CGIdata.has_key("cmd"):
    command = CGIdata["cmd"]
    # Eingabe an altem Prompt anhängen
    txt += " <strong>%s</strong>\n" % command
    # Eingegebener Befehl ausführen + "pwd" (Aktuelles Verzeichnis anzeigen lassen) dranhängen
    out, err = cmd( command + ";echo $~$;pwd" )
    result = out.rsplit("$~$",1)
    current_dir = result[1].strip()
    txt += result[0] + err

# Neues, aktuelles Prompt anhängen
txt += "<strong>%s></strong>" % current_dir

# Ausgaben kürzen und Komprimieren, damit der Client weniger Daten wieder zurück senden muß
# Die Kompression zahlt sich nach zwei, drei Befehlen i.d.R. aus...
stdout_raw = compress( cutLines( txt, maxHistoryLines ) )

txt += "<p><small>compress: %d  decompress: %d</small></p>" % (compressLen, decompressLen)


html = html % {
    "charset"       : locale.getdefaultlocale()[1],
    "uname"         : cmd("uname -a")[0],
    "self"          : os.environ['SCRIPT_NAME'],
    "stdout"        : txt.replace("\n","<br>\n"),
    "stdout_raw"    : stdout_raw,
    "current_dir"   : current_dir
    }

# Seite Ausgeben
putHTML( html )
Slalomsk8er
User
Beiträge: 25
Registriert: Samstag 22. Januar 2005, 19:43

Respect

Ich habe den Code noch nicht testen können aber was ich gelesen habe überzeugt mich (sollte weniger 3D designen und mehr coden).

Danke, ich glaube du hast mich ein gutes Stück weiter gebracht :D
Slalomsk8er
User
Beiträge: 25
Registriert: Samstag 22. Januar 2005, 19:43

Ich bin im Moment im Stress (3D, auf Linux umstellen, Umzug planen und einpacken), deshalb habe ich leider keine Zeit zum coden aber in ca. 3 Monaten bin ich wider foll am Ball.

Gruss, Dominik
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Na, wie gehts voran?

Ich habe heute Anyterm gefunden, ich denke das werf ich so mal in die Runde.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Slalomsk8er
User
Beiträge: 25
Registriert: Samstag 22. Januar 2005, 19:43

Leider nicht wirklich, da immer noch nach einem neuen Heim suche und nun auch noch 2 Webseiten erstellen muss.

Ich habe herausgefunden, dass fopen popen und der Gleichen nicht funktionieren pty muss es sein!

Ich guck mir das mal an danke.
ProgChild
User
Beiträge: 210
Registriert: Samstag 9. April 2005, 10:58
Kontaktdaten:

Slalomsk8er hat geschrieben:Wie mache ich eine transparente Durchreiche zur Konsole (bash, cmd, usw.. )?

Das Ganze sollte eine CGI-HTML-Seite werden mit einem Konsolenfenster und soll sich identisch verhalten, wie die Konsole im Hintergrund (auch ncurses soll 1 zu 1 rüberkommen).
Ich hab die Diskussion hier net so verfolgt, aber du könntest auf deinem System einen Telnet- oder einen SSH-Server installieren. Dann könntest du ein Browser-Applet mit Jython (eine Java implementierung von Python) schreiben, dass zum Telnet oder dem SSH-Server verbindet. Als vorraussetzung muss dann allerdings auf dem Clientrechner Java installiert sein.

Es könnte natürlich sein, dass hier jemand schon einmal diesen Vorschlag gemacht hat, aber das viel mir spontan mal so ein.
Antworten