did it make it through to the list?
-jjOn 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:[EMAIL PROTECTED]">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; > } > } > } >
msg06343/pgp00000.pgp
Description: PGP signature
