did it make it through to the list?

        -jj

On Fri, Jan 17, 2003 at 03:45:14PM +1100, fish wrote:
> hi.  this is a patchish thingy that adds a stream requst servlet to fred,
> despite GJ's advice to not do that.  I'd send a full patch, but it
> seems that cvs.freenet.sourceforge.net is dead, and since I have to go
> home from work,i'm just going to add the required changes to make this
> thing go.
> 
> To Main.java, you need to add the following lines at line #1032 (on my
> copy, which is a week old) in Main.java:
> 
>         setSetValue(params,"mainport.params.defaultServlet.uri", "/default");
>         setSetValue(params,"mainport.params.defaultServlet.method", "GET");
>         setSetValue(params,"mainport.params.defaultServlet.class", 
> "freenet.client.http.RedirectServlet");
>         setSetValue(params,"mainport.params.defaultServlet.name", "Web 
> Interface Redirect");
>         setSetValue(params,"mainport.params.defaultServlet.params.targetURL", 
> "/servlet/nodeinfo/");
> 
> Also, in order to get the metadata out of
> freenet/client/GetRequestProcess.java, I had to change the definition
> of metadataBucket on line #24 to be public.  There is probably a
> better way to achieve this, and I would be appriciated being
> enligtened on this.
> 
> anyhow, the extra file is attached.  apologised for failure to be able
> to cvs diff :(.  i ahte sorceforge :-p
> 
> Anyhow, to the functionality:  This can stream static files of any
> type, sort of... I've only tested it with ogg, mp3, and asf files.  It
> takes two http parameters, ?buffer=number for a buffer time in minutes
> when chunkTime is known, ?htlStep=number for the increment to increase
> HTL on the block requests, and ?htl=number for the htl of the main request,
> you know, the usual shit.  I also attached the readme.txt of the insertion
> stuff, which might interst people - i put the programs to insert stuff at
> http://artificial-stupidity.net/~fish/.
> 
>       - fish

> /* 
>  * Streaming Audio/Video request servelet
>  *
>  * @author <a href="mailto:fish at artificial-stupidity.net">Jaymz Julian</a>
>  * 
>  */
> 
> package freenet.client.http;
> 
> import java.io.*;
> import java.net.*;
> import java.util.*;
> import java.text.DateFormat;
> import javax.servlet.*;
> import javax.servlet.http.*;
> 
> import freenet.*;
> import freenet.node.*;
> import freenet.support.*;
> import freenet.support.io.*;
> import freenet.client.*;
> import freenet.client.events.*;
> import freenet.client.listeners.*;
> import freenet.client.metadata.*;
> import freenet.thread.*;
> 
> // FEC stuff
> import com.onionnetworks.fec.*;
> import com.onionnetworks.util.*;
> 
> public class StreamServlet extends FproxyServlet
> {
>       private boolean firstAccess = true;
>       private Node node;
>       protected static ClientFactory clientFactory;
>       private ServletContext context;
>       int maxHtl=50;
>       
>       public void init()
>       {
>               ServletContext context = getServletContext();
>               node = (Node)context.getAttribute("freenet.node.Node");
>               context = getServletContext();
>               clientFactory = (ClientFactory) 
> context.getAttribute("freenet.client.ClientFactory");
>       }
> 
>       protected void doGet(HttpServletRequest req, HttpServletResponse resp)
>               throws ServletException, IOException
>       {
>               if(firstAccess)
>               {
>                       init();
>                       firstAccess=false;
>               }
>               int myHtl=15;
>               String requestString;
> 
>               try {
>               
>                       requestString= 
> freenet.support.URLDecoder.decode(req.getRequestURI());
>                       // cut off the '/servlet/stream/' part ;)
>                       requestString=requestString.substring(16);
>                       //System.out.println(requestString);
>               } 
>               catch (Exception e)
>               {
>                       PrintWriter pw = resp.getWriter();
>                       resp.setContentType("text/plain");
>                       pw.println("freenet.support.URLDecoder.decode threw.  
> shite.");
>                       return;
>               }
> 
>               // okay, get the main bit o metadata
>               FreenetURI requestUri;
>               try {
>                       requestUri=new FreenetURI(requestString);
>               }
>               catch (MalformedURLException e)
>               {
>                        //writeErrorMessage(e, resp, null, key, null, htlUsed, 
> null, null, tryNum+1)
>                        writeErrorMessage(e, resp, null, requestString, null, 
> myHtl, null, null, 0);
>                        return;
>               }
> 
>               // Get the user specified queue length
>               int queueLength=3;
>               String requestQueueLength=req.getParameter("buffer");
>               if(requestQueueLength!=null)
>               {
>                       try {
>                               
> queueLength=Integer.parseInt(requestQueueLength);
>                       }
>                       catch (Exception e) {}
>               }
>               //System.out.println(queueLength);
> 
>               int htlStep=5;
>               String requestHtlStep=req.getParameter("htlstep");
>               if(requestHtlStep!=null)
>               {
>                       try {
>                               htlStep=Integer.parseInt(requestHtlStep);
>                       }
>                       catch (Exception e) {}
>               }
>               String requestHtl=req.getParameter("htl");
>               if(requestHtl!=null)
>               {
>                       try {
>                               myHtl=Integer.parseInt(requestHtl);
>                       }
>                       catch (Exception e) {}
>               }
>               
>               // Welcome to 'I hate you' theatre, with your 
>               // host, dj fish!
>               FileBucket metadata = new FileBucket();
>               FileBucket data = new FileBucket();
>               GetRequestProcess rp=new GetRequestProcess(requestUri, myHtl, 
> data, new FileBucketFactory(), 0, true, null);
>               Request r;
>               while((r=rp.getNextRequest()) != null)
>               {
>                       try 
>                       {
>                               Client c = clientFactory.getClient(r);
>                               c.start();
>                       }
>                       catch (IOException e)
>                       {
>                               PrintWriter pw = resp.getWriter();
>                               resp.setContentType("text/plain");
>                               pw.println("Society has collapsed!");
>                               pw.println("Lets build villeges, and towns, and 
> play each other at cricket!");
>                               return;
>                       }
>               }
> 
>               if(rp.failed())
>               {
>                       PrintWriter pw = resp.getWriter();
>                       resp.setContentType("text/plain");
>                       pw.println("ERROR: Your key didn't work.  try a higher 
> htl or something.");
>                       pw.println("Someone should fix the call to 
> writeErrorMessage to display that nice non-threatening freenet error message 
> correctly");
>                       //writeErrorMessage(rp.origThrowable, resp, null, 
> requestString, null, myHtl, null, null, 1);
>                       return;
>               }
> 
>               // This is incredibly nasty - what's the *correct* way to do 
> this?
>               ReadInputStream myMetadataStream=new 
> ReadInputStream(rp.metadataBucket.getInputStream());
>               // skip ahead to the main data....
>               try
>               {
>                       while(!myMetadataStream.readToEOF('\n', 
> '\r').equalsIgnoreCase("Document"));
>               }
>               catch (Exception e)
>               {
>                       PrintWriter pw = resp.getWriter();
>                       resp.setContentType("text/plain");
>                       pw.println("Shouldn't happen...");
>                       return;
>               }
>               FieldSet streamMetadata=new FieldSet();
>               streamMetadata.parseFields(myMetadataStream);
> 
>               // Check that this is a correct stream
>               FieldSet streamSpecific=streamMetadata.getSet("Stream");
>               if(streamSpecific == null)
>               {
>                       PrintWriter pw = resp.getWriter();
>                       resp.setContentType("text/plain");
>                       pw.println("Invalid stream format: 
> "+streamSpecific.get("Stream.Format"));
>                       return;
>               }
>               if( !streamSpecific.get("Format").equalsIgnoreCase("Fish") &&
>                       
> !streamSpecific.get("Format").equalsIgnoreCase("fproxy") )
>               {
>                       PrintWriter pw = resp.getWriter();
>                       resp.setContentType("text/plain");
>                       pw.println("Invalid stream format: 
> "+streamSpecific.get("Format"));
>                       return;
>               }
> 
>               // get the URI
>               String myUri=streamSpecific.get("uri");
>               if(myUri==null)
>               {
>                       myUri=requestString;
>               }
> 
>               String mimetype=streamSpecific.get("type");
>               if(mimetype==null)
>               {
>                       mimetype="audio/ogg";
>               }
>               
>               String headerKey=streamSpecific.get("header");
>               if(headerKey==null)
>               {
>                       headerKey="false";
>               }
> 
>               // don't you love these big try/catch waterfalls, it's so much 
> nicer
>               // than Integer,parseInt behaving sanely, yes.
>               int myStartChunk, myEndChunk, chunkSeconds, fecType, fecn, feck;
>               try {
>                       
> myStartChunk=Integer.parseInt(streamSpecific.get("StartChunk"), 16);
>               } catch (Exception e) {
>                       myStartChunk= -1;
>               }
>               
>               try {
>                       
> myEndChunk=Integer.parseInt(streamSpecific.get("EndChunk"), 16);
>               } catch (Exception e) {
>                       myEndChunk= -1;
>               }
>               
>               try {
>                       
> chunkSeconds=Integer.parseInt(streamSpecific.get("ChunkSeconds"), 16);
>                       // if chunk seconds exists. we should adjust the queue 
> length to be in minutes!
>                       int t=queueLength*60;
>                       queueLength=t/chunkSeconds;
> 
>                       // round up, not down!
>                       if((queueLength*chunkSeconds)<t)
>                               queueLength++;
>               } catch (Exception e) {
>                       chunkSeconds=0;
>               }
>               
>               try {
>                       fecType=Integer.parseInt(streamSpecific.get("fecType"), 
> 16);
>               } catch (Exception e) {
>                       fecType= -1;
>               }
>               
>               FieldSet fecSpecific=streamSpecific.getSet("fec");
>               try {
>                       fecn=Integer.parseInt(fecSpecific.get("n"), 16);
>               } catch (Exception e) {
>                       fecn= -1;
>               }
>               
>               try {
>                       feck=Integer.parseInt(fecSpecific.get("k"), 16);
>               } catch (Exception e) {
>                       feck= -1;
>               }
> 
>               // For some bizzare reason, not setting this *first* will
>               // cause my particular JVM to shit itself in a rather unfun
>               // way.  AngyMunkey!
>               //
>               // This being said, on blackdown's 1.3 JVM, which co-incidently 
> is 
>               // the ONLY one which will both compile and run fred on my 
> system,
>               // reching the end of this function will sig11 the JVM anyhow.
>               // I believe this to be sun/blackdown's anti-kiddie-porn filter 
> :-p.
>               //
>               // So, waht I need, is a way to signal the JVM that this is 
> just audio :-p.
>               resp.setStatus(HttpServletResponse.SC_OK);
>               resp.setContentType(mimetype);
>               OutputStream out = resp.getOutputStream();
> 
>               // Get the FEC decoder
>               FECCode 
> fecbitch=FECCodeFactory.getDefault().createFECCode(feck, fecn);
> 
>               StreamChunkRequestor[] requestQueue=new 
> StreamChunkRequestor[queueLength];
>               // fill the head of the queue
>               int currentChunk=myStartChunk;
>               for(int c=0;c<queueLength;c++)
>               {
>                       // get the ASF or other encapsulation format header if 
> it exists (as key 0)
>                       if(c==0 && headerKey.equalsIgnoreCase("true"))
>                       {
>                               requestQueue[c]=new StreamChunkRequestor(myUri, 
> 0, fecType, fecn, feck, fecbitch, htlStep);
>                               if(currentChunk==0)
>                                       currentChunk++;
>                       }
>                       else
>                       {
>                               requestQueue[c]=new StreamChunkRequestor(myUri, 
> currentChunk, fecType, fecn, feck, fecbitch, htlStep);
>                               currentChunk++;
>                       }
>                       Thread t=new Thread(requestQueue[c]);
>                       t.start();
>               }
>               while(true)
>               {
>                       boolean allWorking=true;
>                       boolean failedBlock=false;
>                       // check if the queue is full
>                       for(int c=0;c<queueLength;c++)
>                       {
>                               // this request is finished progress
>                               if(requestQueue[c].inProgress==true)
>                               {
>                                       allWorking=false;
>                               }
>                               else
>                               {
>                                       // check if all is kosher, or if there
>                                       // is a block in the queue that failed 
> to 
>                                       // retrieve
>                                       if(requestQueue[c].success==false)
>                                               failedBlock=true;
>                               }
>                       }
> 
>                       // if we have all of the blocks in the queue, head on up
>                       if(allWorking)
>                       {
>                               if(requestQueue[0].success)
>                               {
>                                       // write the data at the head of the
>                                       // queue.
>                                       out.write(requestQueue[0].outputData);
>                                       // pop the top
>                                       for(int c=1;c<queueLength;c++)
>                                               
> requestQueue[c-1]=requestQueue[c];
> 
>                                       // append the next block to the queue
>                                       // if we havn't failed a block
>                                       if(!failedBlock)
>                                       {
>                                               requestQueue[queueLength-1]=new 
> StreamChunkRequestor(myUri, currentChunk, fecType, fecn, feck, fecbitch, 
> htlStep);
>                                               Thread t=new 
> Thread(requestQueue[queueLength-1]);
>                                               t.start();
>                                               currentChunk++;
>                                       }
>                               }
>                               else
>                               {
>                                       // When you walk away, you don't hear 
> me say, Please.... oh baby, don't go
>                                       // simple and clean is the way you're 
> making me feel tonight!
>                                       //System.out.println("Cleanly 
> finished!");
>                                       return;
>                               }
>                       }
>                       try {
>                               Thread.sleep(1000);
>                       } catch (InterruptedException e) {}
>               }
>       }
> 
>       class StreamPartRequestor implements Runnable
>       {
>               public boolean success;
>               public boolean inProgress;
>               public int finalSize;
>               public FileBucket data = new FileBucket();
>               FreenetURI uri;
>               int htl;
>               FECCode fecbitch;
>               int htlStep;
>               
>               StreamPartRequestor(String myuri, FECCode ifecbitch, int 
> iHtlStep)
>               {
>                       try {
>                               uri=new FreenetURI(myuri);
>                       } catch (Exception e) {
>                               System.out.println("Arg! Bad things happened in 
> StreamPartRequestor");
>                       }
>                       htl=0;
>                       success=inProgress=false;
>                       finalSize=0;
>                       fecbitch=ifecbitch;
>                       htlStep=iHtlStep;
>               }
> 
>               public void run()
>               {
>                       inProgress=true;
>                       htl=htl+htlStep;
>                       //System.out.println("Requesting "+uri+" at htl="+htl);
>                       
>                       GetRequestProcess rp=new GetRequestProcess(uri, htl, 
> data, new FileBucketFactory(), 0, true, null);
>                       Request r;
>                       while((r=rp.getNextRequest()) != null)
>                       {
>                               try 
>                               {
>                                       Client c = clientFactory.getClient(r);
>                                       c.start();
>                               }
>                               catch (IOException e)
>                               {
>                                       System.out.println("You are here.  (You 
> shouldn't be... bad things in StreamPartRequestor.run())");
>                               }
>                       }
>                       if(!rp.failed())
>                       {
>                               // Get the final size for the completed block
>                               try {
>                                       ReadInputStream myMetadataStream=new 
> ReadInputStream(rp.metadataBucket.getInputStream());
>                                       // skip ahead to the main data....
>                                       try
>                                       {
>                                               
> while(!myMetadataStream.readToEOF('\n', '\r').equalsIgnoreCase("EndPart"));
>                                       } catch (Exception e) {}
>                                       
>                                       FieldSet streamMetadata=new FieldSet();
>                                       
> streamMetadata.parseFields(myMetadataStream);
>                                       FieldSet 
> streamSpecific=streamMetadata.getSet("Stream");
>                                       FieldSet 
> fecSpecific=streamSpecific.getSet("fec");
>                                       
> finalSize=Integer.parseInt(fecSpecific.get("actualSize"), 16);
>                               } catch (Exception e) {}
> 
>                               success=true;
>                               //System.out.println("Retrieved block!  final 
> size is "+finalSize);
>                       }
>                       inProgress=false;
>               }
>       }
> 
>       class StreamChunkRequestor implements Runnable
>       {
>               public boolean success;
>               public boolean inProgress;
>               String myUri;
>               int myChunk;
>               int fecType;
>               int fecn;
>               int feck;
>               int htlStep;
>               byte [] outputData;
>               FECCode fecbitch;
> 
>               // welcome to iFreenet!
>               StreamChunkRequestor(String iUri, int iChunk, int ifecType, int 
> ifecn, int ifeck, FECCode ifecbitch, int iHtlStep)
>               {
>                       success=false;
>                       inProgress=false;
> 
>                       myUri=iUri;
>                       myChunk=iChunk;
>                       fecType=ifecType;
>                       fecn=ifecn;
>                       feck=ifeck;
>                       fecbitch=ifecbitch;
>                       htlStep=iHtlStep;
>               }
> 
>               public void run()
>               {
>                       inProgress=true;
>                       StreamPartRequestor myRequestors[]=new 
> StreamPartRequestor[fecn];
>                       
>                       // request the chunks
>                       for(int c=0;c<fecn;c++)
>                       {
>                               String realUri=myUri+"/"+myChunk+"/"+c;
>                               myRequestors[c]=new 
> StreamPartRequestor(realUri, fecbitch, htlStep);
>                       }
>       
>                       int retrievedBlocks;
>                       int progressBlocks;
>                       do
>                       {
>                               retrievedBlocks=0;
>                               progressBlocks=0;
>                               for(int c=0;c<fecn;c++)
>                               {
>                                       if(myRequestors[c].inProgress==false)
>                                       {
>                                               
> if(myRequestors[c].success==true)
>                                               {
>                                                       retrievedBlocks++;
>                                               }
>                                               else 
> if(myRequestors[c].htl<maxHtl)
>                                               {
>                                                       Thread t=new 
> Thread(myRequestors[c]);
>                                                       t.start();
>                                                       progressBlocks++;
>                                               }
>                                       }
>                                       else
>                                       {
>                                               progressBlocks++;
>                                       }
>                               }
>                               //System.out.println("Retrieved Blocks: 
> "+retrievedBlocks);
>                               //System.out.println("Blocks in progress: 
> "+progressBlocks);
>                               // sleep for a second
>                               try {
>                                       Thread.sleep(1000);
>                               } catch (InterruptedException e) {}
>                       } while(retrievedBlocks<feck && progressBlocks>0);
> 
>                       if(retrievedBlocks>=feck)
>                       {
>                               
>                               // create the structures for the decoder
>                               Buffer[] landingZone= new Buffer[feck];
>                               int[] index=new int[feck];
>                               int lastBlock=0;
>                               int finalSize=0;
> 
>                               for(int c=0;(c<fecn && lastBlock<feck);c++)
>                               {
>                                       if(myRequestors[c].success==true)
>                                       {
>                                               try {
>                                                       // nasty, nasty, nasty, 
> nasty dounle hadnling here....
>                                                       byte[] b=new 
> byte[(int)myRequestors[c].data.size()];
>                                                       
> myRequestors[c].data.getInputStream().read(b);
>                                                       
> landingZone[lastBlock]=new Buffer(b);
>                                                       
> finalSize=myRequestors[c].finalSize;
>                                                       
>                                               } catch (IOException e)
>                                               {
>                                                       // somebody fucking 
> some something!!!!
>                                               }
>                                               index[lastBlock]=c;
>                                               lastBlock++;
>                                       }
>                               }
>                               
>                               // I'd prefer to use System.arraycopy() here, 
> but it
>                               // seems to not quite do what I want, according 
> to the
>                               // code I am reading.  Arg.
>                               outputData=new byte[finalSize];
>                               int off=0;
>                               for(int c=0;(c<feck && off<finalSize);c++)
>                               {
>                                       for(int d=0;(d<landingZone[c].b.length 
> && off<finalSize);d++)
>                                       {
>                                               
> outputData[off]=landingZone[c].b[d];
>                                               off++;
>                                       }
>                               }
> 
>                               // the chills that 
>                               // you spill up my back
>                               // keep me filled 
>                               // with satistfaction
>                               // when we're done
>                               // satisfaction 
>                               // oh what's the harm?
>                               success=true;
>                       }
> 
>                       inProgress=false;
>               }
>       }
> }
> 




-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 230 bytes
Desc: not available
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20030122/23e45cd8/attachment.pgp>

Reply via email to