FileIO-Net, Part I (09/2001, Dir 8)

In diesem Bereich befinden sich Artikel und Tutorials zum Thema Director.

Moderatoren: Bär, Admin

Antworten
Admin
Site Admin
Beiträge: 41344
Registriert: 07.02.2006, 2006 16:09
Wohnort: München
Kontaktdaten:

FileIO-Net, Part I (09/2001, Dir 8)

Beitrag von Admin » 12.02.2006, 2006 19:47

FileIO-Net

Die Funktionalität Dateien auf einem lokalen Rechner zu lesen oder zu schreiben, gehört seit jeher zur Standardausrüstung von Director. Implementiert wurde diese Schnittstelle durch das stets im Lieferumfang von Director enthaltene „FileIO“ Xtra. Dies ist im Vergleich zu internen Lingo Funktionen jedoch etwas umständlich, da das Xtra immer noch instantiert werden muss und eine Dokumentation, bis auf die Funktionsauflistung über die „interface()“ Funktion leider nicht existiert.

Alternativ stehen jedoch einige andere Xtras, wie z.B. „BuddyAPI“ oder „FileXtra3“ zur Verfügung, die kostengünstig oder wie im Fall von „FileXtra3“ sogar kostenlos die gleichen und sogar noch mehr Aufgaben erledigen können. Auch die internen „SetPref()“ und „GetPref()“ Funktionen können, wenn auch sehr eingeschränkt, Datei Lese- und Schreibvorgänge übernehmen.

Völlig anders ist die Situation jedoch, wenn es darum geht Dateien auf einem Server zu lesen bzw. zu schreiben. Nicht nur für Shockwave Anwendungen, sondern auch für CD-Rom Projekte wird diese Funktionalität häufig benötigt. Eines der typischen und an dieser Stelle gerne genannten Beispiele ist das Lesen und Schreiben einer Highscore-Liste im Rahmen eines Spiels. Es wäre also wünschenswert eine einfache und flexible Schnittstelle für eine solche Funktionalität zu haben. Diese Schnittstelle mit dem Arbeitsbegriff „FileIO.NET“ soll im Rahmen dieser und der nächsten „LingoPark Tipps & Scripts“ erstellt werden.

Wichtig ist in diesem Zusammenhang noch zu erwähnen, dass mit „Dateien“ im folgenden ausschließlich ASCII Dateien gemeint sind, d.h. keine Binärdateien wie z.B. Bilder oder ähnliches.


Server Scripts

Die Funktionalität von serverseitigen Dateioperationen ist im Vergleich zu einfachen Dateioperationen auf einem lokalen Rechner schon ein wenig komplexer. Deshalb soll zunächst einmal analysiert werden, was genau im Hintergrund geschieht.

Eine CD-Rom oder auch Shockwave Anwendung wird stets lokal ausgeführt, d.h. im Fall eines Shockwave wird die Datei zuerst auf den lokalen Rechner heruntergeladen und anschließend aus dem Browser Cache heraus ausgeführt. Alle entsprechenden Lese- und Schreibbefehle, z.B. über die „GetPref() / SetPref()“ Funktionen beziehen sich also automatisch auf den lokalen Rechner.

Eine „remote“ Datei auf einem Server zu lesen, lässt sich dagegen über die interne „getNetText()“ Funktion bewerkstelligen. Eine entsprechende Datei auf einen Server zu schreiben, kann jedoch nur über ein auf dem Server ausgeführtes Server Script bewerkstelligt werden. Und genau an dieser Stelle tritt die Problematik auf. Es wird ein entsprechendes Server Script benötigt, welches die gleiche Funktionalität wie beispielsweise das „FileIO“ Xtra auf Seiten des Servers übernimmt. Ein solches Script kann u.a. in Sprachen wie z.B. Perl, ASP, Java oder PHP erstellt werden (im Rahmen der Erstellung von „FileIO.NET“ soll exemplarisch auf die Verwendung von Perl und PHP eingegangen werden, da dies wohl die am weitesten verbreiteten Scriptsprachen sind).

Über die „getNetText()“ und die „postNetText()“ Funktion können diese Scripte aus Lingo heraus aufgerufen werden. Dabei können dem Script auch Daten in Form von Parametern in Form einer Property Liste übergeben werden. Im Fall eines Schreibvorgangs sollen dem Script z.B. der Name der Datei und die zu schreibenden Daten übergeben werden. Entsprechend wird von dem Script anschließend eine Rückmeldung über Erfolg oder Misserfolg erwartet.

Exemplarisch sind im folgenden einmal zwei Funktionen, jeweils aus einem Perl und einem PHP Script dargestellt:

Code: Alles auswählen

PHP:
function read_from_file ($file) {		// read data from file
	$fh = fopen($file, "r");
	if ($fh) {
	  $data = fread($fh, filesize($file));
	  fclose ($fh);
  	  return $data;
	} else {
	  return "#FileIO Error: cannot open file $file";
	}
}

Code: Alles auswählen

Perl:
sub write_to_file () {			# write data to file
	my ($file, $data) = @_;
	if (!open (FH, "> $file")) {
	  return "#FileIO Error: cannot write to file $file";
	} else {
	  print FH $data;
 	  close (FH);
	  return 1;
	}
}
Die „FileIO-NET“ Funktionalität wird später jeweils in einem Perl und einem PHP Script implementiert werden, welche dann der CD-Rom in diesem Heft beiliegen werden. Beide Scripte verfügen über exakt die gleichen Funktionen und Rückgabewerte, so dass zu jeden Zeitpunkt das Server Script gewechselt werden kann ohne die entsprechenden Scripte in Lingo ändern zu müssen. Dazu jedoch mehr im zweiten Teil von „FileIO-NET“.

Wie sieht also der eigentliche Verlauf des Lese- und Schreibvorgangs einer Datei auf einem Server aus? Im Prinzip genauso bzw. ähnlich wie bei lokalen Dateioperationen. Um einmal kurz vorweg zu greifen, und um zu sehen wie es nachher aussehen soll, hier ein Beispiel für einen Schreibvorgang mit „FileIO-NET“:

Code: Alles auswählen

write_file („http://www.myserver.de/myscript.php“, "test.txt", "Dies ist ein Test")
Dahinter verbirgt sich eine Reihe von Vorgängen, die nun Schritt für Schritt analysiert werden sollen.


Die „NetOperation“ Klasse

Zur Kommunikation mit dem Server Script soll ein allgemeines generisches Lingo Objekt erzeugt werden, dass die Verhandlung mit dem Server Script übernimmt. Der Grund dafür ist einfach. Im Gegensatz zu lokalen Operationen kann es nämlich bei Netzoperationen keine direkte Antwort auf eine Anfrage geben, da zu viele Faktoren wie die Geschwindigkeit der Verbindung, die Größe der Daten, die Auslastung des Servers etc. eine entsprechende Verzögerung der Antwort bewirken. Daher spricht man hier von „asynchronen“ Operationen, d.h. im Gegensatz zu einem Mausklick, der sofort einen „mouseDown“ Event auslöst, hat beispielsweise eine „getNetText()“ Operation keine sofortigen Auswirkungen.

Es bietet sich also an dafür ein Objekt zu erstellen, welches den Auftrag bekommt ein Server Script zu kontaktieren, dieses mit entsprechenden Informationen (z.B. Anfrage nach dem Inhalt einer Datei) zu versorgen und auf eine Antwort zu warten. Währenddessen können z.B. Animationen oder auch User Operationen wie Mausklicks weiter durchgeführt werden, denn sobald das Objekt seine Antwort vom Server Script bekommen hat, soll es sich selbständig zurückmelden und die Antwort an einer vorher ausgemachten Stelle abliefern.

Das Objekt verfügt lediglich über ein paar, ziemlich selbsterklärende Properties: pNetID speichert die der Netzoperation zugewiesene NetID, pTimeOut bezeichnet das Timeout Zeitlimit für die Server Script Antwort, pUrl die Adresse des Server Scripts, pCallbackObj das Script oder Objekt in welchem sich der Handler pCallbackHandler befindet, dem später die Antwort des Server Scripts übergeben wird.

Eine Besonderheit ist bei der Erzeugung des Objektes im „new()“ Handler zu finden. Der Konstruktor gibt keine Referenz zur erzeugten Objektinstanz (me) zurück, d.h. ein „return me“ Statement existiert nicht. Der Grund ist einfach, es wird nicht benötigt da keine Referenz zum Objekt nach außen weitergeben wird. Stattdessen wird ein „Timeout Objekt“ mit einem Namen bestehend aus der zugewiesenen NetID und der Url erzeugt, welches eine Referenz zum Objekt speichert und dieses alle 10 Millisekunden (dieser Wert ist natürlich frei wählbar und an dieser Stelle nur exemplarisch gewählt) über einen angegebenen Handler kontaktiert. Das erzeugt Objekt existiert also nur solange eine Referenz zur erzeugten Instanz im Timeout Objekt besteht. Wird das Timeout Objekt gelöscht, so wird damit auch das „NetOperation Objekt“ gelöscht.

Code: Alles auswählen

-- --------------------------
-- NetOperation Class
-----------------------------

property pNetID
property pTimeOut
property pUrl
property pCallbackObj
property pCallbackHandler

on new (me, myUrl, myMode, myData, myCallbackObj, myCallbackHandler)
  pNetID = FALSE
  pTimeOut = the milliSeconds + (60*1000)
  pUrl = myUrl
  pCallbackObj = myCallbackObj
  pCallbackHandler = myCallbackHandler
  case myMode of
    #post:
      pNetID = postNetText(myUrl, myData)
    #get: 
      pNetID = getNetText(myUrl, myData)
    otherwise
      put "#FileIO-Net_ERROR: no operation mode specified"
  end case
  if pNetID then timeout(pNetID & "_" & pUrl).new(10, #mCheckNetOp, me)
end new
Das Parent Script verfügt über lediglich eine öffentliche Methode (streng genommen sind natürlich alle Methoden in Lingo öffentlich zugänglich, aber es sollte zum guten Ton gehören dennoch eine eigene Kennzeichnung wie z.B. „mHandlerName“ zu verwenden). Diese Methode ist dazu da den Status der Netzoperation zu überprüfen, d.h. das Objekt prüft ob die Operation innerhalb des vorgegebenen Zeitrahmens (pTimeout) erledigt wurde, ob ein Fehler aufgetreten ist, oder das Ergebnis in Form einer Antwort von Seiten des Servers vorliegt.

Code: Alles auswählen

on mCheckNetOp (me)
  if pNetID then
    if the milliSeconds > pTimeOut then 
      me.netOpTimeout()
    else
      if netDone(pNetID) then
        if netError(pNetID) = "OK" then
          me.netOpDone()
        else
          me.netOpError()
        end if
      end if  
    end if
  end if
end mCheckNetOp
In jedem der drei möglichen Fälle wird ein entsprechender Handler (hier die privaten Methoden) im Objekt aufgerufen. Im Fall eines Timeout wird die Netzwerkoperation beendet, im Fall eines Fehlers der Fehler ausgewertet und im Fall einer positiven Antwort diese über die „netTextResult()“ Funktion ausgelesen. Anschließend wird in allen Fällen das „Timeout Objekt“ und damit auch die einzige Referenz zum „NetOperation Objekt“ gelöscht, und dem Callback Handler im Callback Script bzw. Objekt das Resultat der Operation übergeben:

Code: Alles auswählen

-- net operation done
on netOpDone (me)
  res = netTextResult(pNetID)
  me.kill()
  call (pCallbackHandler, pCallbackObj, #ok, res)
end netOpDone

-- net operation time out
on netOpTimeout (me)
  netAbort(pNetID)
  me.kill()
  call (pCallbackHandler, pCallbackObj, #timeout, pUrl)
end netOpTimeout

-- net operation error
on netOpError (me)
  err = netError(pNetID)
  errStr = me.netErrorString(err)
  errMsg = err && "(" & errStr & ")"
  me.kill()
  call (pCallbackHandler, pCallbackObj, #error, pUrl, errMsg)
end netOpTimeout

-- destroy object
on kill (me)
  timeout(pNetID & "_" & pUrl).forget()
end kill
Die Funktion „netErrorString()“ wird an dieser Stelle nicht aufgeführt, da hier lediglich eine lange Liste mit möglichen Error Codes und ihren entsprechenden Texterklärungen stehen.


Fazit

Die Erstellung des eben vorgestellten „NetOperation Objekt“ war der erste Schritt auf dem Weg zu Erstellung der „FileIO-NET“ Funktionalität (die Erstellung der PHP bzw. Perl Scripte mal nicht mitgerechnet, da im zweiten Teil von „FileIO-NET“ noch näher darauf eingegangen werden soll). Mit Hilfe eines solchen Objekts können nun beliebige Netzwerk Operationen durchgeführt werden, also nicht nur im Rahmen der „FileIO-NET“ Funktionalität. In dieser Hinsicht ist dieser erste Teil für sich genommen also auch ein in sich abgeschlossenes Thema.

Für eine andere Anwendung könnte ein solches Objekt z.B. folgendermaßen verwendet werden:

Code: Alles auswählen

myUrl = “http://www.directordevelopers.com/index.html”
(script "NetOperation Class").new (myUrl, #get, [], script "Test", #net_callback)
In diesem Fall würde ein Objekt erzeugt und beauftragt werden die Datei „index.html“ auszulesen und das Ergebnis an den Handler „net_callback()“ im Script „Test“ (das Movie Script, welches diesen Handler enthält) zu übergeben. Dieser Handler könnte z.B. das Ergebnis, in diesem Fall den HTML-Quelltext der Seite dem HTML-Property eines Textdarstellers zuweisen, und so die HTML-Seite auf der Bühne darstellen:

Code: Alles auswählen

on net_callback (me, myStatus, myData, myMsg)
  if myStatus = #ok then
    member(“lingopark”).html = myData
  end if
end net_callback
Im zweiten Teil dieses Artikels wird dann ganz konkret auf die Anwendung des „NetOperation Objekt“ im Bezug auf die „FileIO-NET“ Funktionalität eingegangen und die entsprechenden Funktionalitäten und Beispielscripts erstellt.


Autor: Martin Kloss

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast