About Monkey 2 › Forums › Monkey 2 Programming Help › ProcessReader (helper)
This topic contains 0 replies, has 1 voice, and was last updated by
nerobot 1 year, 11 months ago.
-
AuthorPosts
-
May 4, 2017 at 3:16 am #8103
ProcessReader class
This class provide reading of process output via sync and async variants.
There are pooling-like system to reduce instances creation based on methods Obtain and Recycle.
Also you can stop all processes by simple call to static method ProcessReader.StopAll().
Sync variant should be called inside of fiber:
Monkey123456789101112New Fiber( Lambda()Local reader:=ProcessReader.Obtain()Local cmd:=_mx2ccPath+" makeapp -parse -geninfo ~q"+pathOnDisk+"~q"Local output:=reader.Run( cmd )ProcessReader.Recycle( reader )' do something with 'output'End )Async variant should use events to get data: Finished, PortionRead, Error (new fiber is created inside of RunAsync):
Monkey123456789101112131415Local reader:=ProcessReader.Obtain()' react on read portionreader.PortionRead+=Lambda( portion:String )Print "output: "+portionEnd' react on finishedreader.Finished+=Lambda( output:String,exitCode:Int )' do something with full output / exitCode here' or just recycle readerProcessReader.Recycle( reader )End' startLocal cmd:=_mx2ccPath+" makeapp -parse -geninfo ~q"+pathOnDisk+"~q"Local output:=reader.RunAsync( cmd )ProcessReader.Recycle() looks not good, maybe will be better to auto-recycle reader when it finished.
Full sources:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205#rem monkeydoc The ProcessReader class.Allow us to read output from process.We can reuse this class with any commands.Each command starts new process.You should to wait until work is finished - if you run while process already running then nothing happen.There are 2 usage scenarios: RunAsync and Run.With RunAsync we get output by PortionRead and Finished events.This is not blocked method.With Run we get output as result of this call.This is blocked method.Both methods are using Fiber to waiting process finished.#endClass ProcessReader#rem monkeydoc Invoked when a process finishes execution.#endField Finished:Void( output:String,exitCode:Int )#rem monkeydoc Invoked when read portion of output from process.#endField PortionRead:Void( output:String )#rem monkeydoc Invoked when a process finishes execution AND exitCode <> 0.#endField Error:Void( exitCode:Int )#rem monkeydoc Obtain a reader instance.#endFunction Obtain:ProcessReader()Local r:ProcessReaderIf _recycled.Emptyr=New ProcessReaderElser=_recycled[0]_recycled.Remove( r )Endifr.Finished=Nullr.PortionRead=Nullr.Error=Null_items.Add( r )Return rEnd#rem monkeydoc Recycle a reader instance. So we can get it again using Obtain.#endFunction Recycle( r:ProcessReader )_items.Remove( r )r.Stop()_recycled.Add( r )End#rem monkeydoc Stops all obtained readers if them are running and not recycled.#endFunction StopAll()For Local r:=Eachin _itemsr.Stop()NextEnd#rem monkeydoc Async reading of process. You should to subscribe on (at least) Finished event to get result.This method can be used without creation of new Fiber.If started while process already running - nothing happen.#endMethod RunAsync( command:String )If _running ReturnNew Fiber( Lambda()RunInternal( command )End )End#rem monkeydoc Sync reading of process.This method must be used with creation of new Fiber, because it uses Future to waiting for process finished.Return full output of a process.If started while process already running - immediately return an empty string.#endMethod Run:String( command:String )If _running Return ""Return RunInternal( command )End#rem monkeydoc Terminate process execution.#endMethod Stop()If _running Then _process.Terminate()End#rem monkeydoc Is reading currently in progress.#endMethod IsRunning:Bool()Return _runningEndProtectedMethod New()EndPrivateField _process:ProcessField _output:StringField _running:BoolField _stdoutWaiting:Future<Bool>Field _stdoutOpen:Bool,_procOpen:BoolGlobal _items:=New Stack<ProcessReader>Global _recycled:=New Stack<ProcessReader>Method RunInternal:String( cmd:String )If Not Start( cmd )Print "Failed to start process '"+cmd+"'"Return ""Endif' waiting for the end_stdoutWaiting=New Future<Bool>_stdoutWaiting.Get()_stdoutWaiting=NullReturn _outputEndMethod Start:Bool( cmd:String )If _running Return FalseLocal process:=New Processprocess.Finished=Lambda()_procOpen=FalseUpdateRunning()Endprocess.StdoutReady=Lambda()Local stdout:=process.ReadStdout()If stdoutstdout=stdout.Replace( "~r~n","~n" ).Replace( "~r","~n" )_output+=stdoutPortionRead( stdout )Else_stdoutOpen=FalseUpdateRunning()EndifEndIf Not process.Start( cmd ) Return False_process=process_running=True_procOpen=True_stdoutOpen=True_output=""Return TrueEndMethod UpdateRunning()If Not _running Or _procOpen Or _stdoutOpen Return_running=FalseIf _stdoutWaiting Then _stdoutWaiting.Set( True )Local code:=_process.ExitCodeFinished( _output,code )If code<>0 Then Error( code )EndEndPrivate' Extends ProcessReader - to get access to protected New()Class ProcessBridge Extends ProcessReaderFunction Create:ProcessReader()Return New ProcessReaderEndEnd -
AuthorPosts
You must be logged in to reply to this topic.