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; } } }Title: Fishsite tools v3.0.18
Fishsite tools v3.0.18
A CLI Freenet site insertion tool.
Contact: [EMAIL PROTECTED]
Contents
What it requires
- Freenet
- On non-windows platformas, Python 2.0 or later.
For Windows users, this is not required.
Features
This section describes the various features of fishtools before we get into how to actually use it.
Site types
If you want to make a freesite you first must decide what type of of site to use. There are two types of keys (DBR or edition) combined with two formats (static or manifest), for a total of four combinations.
DBR
DBR (date based redirects) are metadata keys that point to a new file every time a set interval occurs. These are useful for a site that will update on a set schedule.
Advantage:
- The url for the site never changes.
Disadvantages:
- You can't update your site more frequently than the frequency of the DBR.
- If you don't insert the new edition before the DBR shifts over, your site will seem to be broken.
Examples:
- The Freedom Engine: SSK@40rBjVda8pC-Kq04jUurIAb8IzAGcPAgM/TFE//
- Cruft: SSK@FaP94HgrzsEY2BSW8rp4ZNHnAMUPAgM/cruft//
Edition
An edition site is actually a collection of freesites under the same SSK with the same name, with an edition number added. It is useful for sites that will update on an irregular basis or for "one shot" freesites.
Advantage:
- You can update at any interval you want.
Disadvantage:
- The URL for your site changes with every edition.
- In order for people to find your new editions, you have to link to future editions that don't exist yet.
Examples:
- Fishtools: SSK@kWu5Osv~VAI3-kH7z8QIVxklv-YPAgM/fishtools/31//
- Quack Experimental Freesite: tyG6z6Evys7R9i1LKfA4IgppVx0PAgM/QEF/6//
Manifest
This is the traditional format for a freesite. The key used for a manifest site points to a metadata file called a manifest. This file contains the CHK's of all the files contained in the manifest.
Static
This type of site does not use a manifest. Each file has its own edition number or DBR. This allows each file in a site to be updated individually.
Link rewriting
Fishtools will rewrite your html to change local paths to the correct freenet keys. It will also rewrite internet URL's to pass through the anonymitiy filter.
Automatic feedback forms
If you add the text "feedbackfirstFeedback and feedbackNumber configration options.
Automatic edition navigation
Fishtools will replace "editionImage0" with the image for the current edition, "editionImage1" for current edition+1, and so on through 20. It will also replace "editionLink0" with a link to the current edition's active link (as set by the activeLink configuration option), and so on through "editionLink20". Negative values are allowed both for links and images to refer to previous editions. This currently only works for manifest sites.
CHK Caching
Fishtools will cache generated metadata/generated CHK's, and only refresh files every N days (controlled by the refreshTime configuration option), for easy continued insertion of large files. Changed is defined as file contents, so you can move things around without it all going awry. Also, fishtools
will now check to see if a file is retrivable after a set period of time, and automatically reinsert it if it cannot retrieve it.
Site verification
Fishtools will verify all inserts have made it into freenet in a retrievable state, and will automatically reinsert the content if this is not the case. This is controlled by the verifyInsert configuration option.
As mentioned above, it will also verify data you have previously inserted to ensure that it is still retrivable. This verification occurs after the successful insertion of the current edition. The amount of data that will be verified is controlled by the maxRefresh configuration option. It sets a limit on the number of megabytes that gets inserted each session. This includes both new content and verified content.
Automatic FEC encoding
Fishtools will automaticially FEC encode large files (now with the new "doesn't crash your node anymore" feature). Splitfile sizes other than 262144 don't seem to download correctly with fproxy, so I've hardcoded this figure. Can someone please look at this?
Multiple Node Support
Fishtools now supports inserting to multiple nodes. The fcpHost, fcpPort and fcpMode configurations options are used to enable this feature.
Configuration
Fishtools uses two files for configuration: globalconfig and a site-specific file. All options are valid in both files. Fishtools will first use the options specified in globalconfig and then read the site-specific file for additional options. Note that the site-specific options override globalconfig options.
All options are specified in "option=value" format and all values are case sensitive.
See the included globalconfig.sample for an example globalconfig and fishland and fishtools for examples of site-specific configurations.
Options
activeLink- file name of the active link image for edition freesites
dbrDays- the number of days before the DBR switches to a new edition (default freenet value is one, basically, this is how often you have to reinsert your DBR site)
fcpHost- host for the freenet server (default 127.0.0.1)
fcpHostN- for multiple node support, specify each host with multiple
fcpHostoptions (fcpHost1,fcpHost2, etc)
fcpMode- how to load balance between multiple nodes. Options are:
load- choose the node with the lowest load. Note that this will not work on a stock node, as it utilises my ClientInfo patch, which hasn't been integrated in the main branch (yet)
random- choose a random node for each request
roundRobin- step through the nodes sequentually
fcpPort- port for the freenet server (default 8481)
- for multiple node support, specify the ports for the corresponding hosts with multiple
fcpPostoptions (fcpPort1,fcpPort2, etc)
- for multiple node support, specify the ports for the corresponding hosts with multiple
feedbackNumber- number of feedback slots to generate
firstFeedback- number of the first feedback slot
htl- freenet HTL value for inserts
maxRefresh- the maximum amount of data (new files + refresh files) in megabytes that will be inserted. This is used to limit the amount of data that gets refreshed.
maxThreads- the maximum number of threads to spawn
privateKey- your private key
refreshTime- the number of days after which fishtools should attempt to verify that content is still retrivable
remoteInsert- skip over your local node and insert directly onto the network
seperator- Character used to seperate the site name from the edition number. Default is "/", however was "-" in older versions.
siteDir- filesystem path to the directory where the site files are located
siteName- what the site is called; the bit after your key in the url ("fishland2" in my case)
siteType- the type of site you're inserting. One of:
dbr-manifest- traditional DBR site
dbr-static- static DBR site (probably useless ;)
edition-manifest- traditional edition site
edition-static- static edition site (ala fishtools)
verbose- enables verbose output
verifyInsert- verify that your site actully inserted
Magic Strings
Fishtools will search through your html for the following strings and convert them to their respective features.
- feedbackformhere
- generates a feedback form with
feedbackNumberslots, starting withfirstFeedback. - editionLinkN
- generates the key of a future or past edition. N can have a value of -20 to 20.
- editionImageN
- generates the key of the active link of a future or past edition. N can have a value of -20 to 20
Usage
Inserting a freesite
- Edit globalconfig, with your keys
- Create a file with your site specific information in it (look at fishland or fishtools as examples)
- Make sure that the path you used in your HTML matches the one in globalconfig *exactly*, or things won't work!!!!!
- Switch to the directory that unarchived the program in to
-
- For editions, Run "Fishsite 1 [your config file here]". You can replace '1' with a new starting edition if you already have editions inserted/want to skip some editions
- For a DBR based site, Run "Fishsite [days in future] [your config file here]".
Note on edition sites: Refreshes of manifest based edition sites are *not* fully automated yet - if you run 'Fishsite 0 site', it will insert as a new edition. However, if you run 'Fishsite edition site', it will refresh that edition specifically. You have been warned :)
Inserting a single file
- Switch to the directory that unarchived the program in to
- Edit globalconfig, with your keys
- run "Fishinsert [file] [key]", Where 'key' is one of:
- KSK@wherever - insert a key into the public keyspace.
- SSK@file/whatever - insert a key into your private keyspace at SSK@yourkey/file/whatever. Note that you do not specify your private key on the command line!
Changelog
What's new in 3.0.18
- New documentation - thanks to Wonko the sane for rewriting my crappy documentation.
- Fixed a stupid bug in the edition link generation code - it actully works again, honest! (it worked in 3.0.16, but i broke it fixing a bug in it that I didn't test, oops ^_^)
- Backwards edition links - you can now use editionImage-1 for the image for the previous edition, and editionLink-1 for a link to the previous edition. I don't know why anyone would want this ^_^.
- maxRefresh - You can now limit the number of megabytes that fishtools will refresh.
What's new in 3.0.17.1
- I am an idiot - one of the FEC changes would fuck manifests, speciifcally, the last FEC file inserted would not always make it onto the list. I reverted the change in question, so FEC inserts take up one extra thread than they should again. Oh well!
What's new in 3.0.17
- Multinode support - thanks to Matt Toseland for the initial idea, even if I didn't implent what he actully wanted ;)
- A big lock arouind the FEC encoding phase - this should help with the resource issues
- Stupid bug in the manifest cache code, which the version of python I use would ignore, but triggered on others
What's new in 3.0.16.1
- Typo in edition site code - oops :)
What's new in 3.0.16
- Fixed a critical bug in build scripts
- Fixed issues with subdirectories on windows
- Removed the code to add PAgM to keys
- Edition link generation
- FMB style feedback form generation
- Preliminary html based configuration UI
What's new in 3.0.15
- fix for the bug involving really large files on windows. theoretically.
What's new in 3.0.14
- Massive, Massive, Massive FEC bug fixed - thanks to Taral for pointing this one out (a result of fixing Jaksio's bug in 3.0.10, ironically - I accidently deleted a very important line. Stupid fish)
- Did I mention that bug was massive?
- Added a "verbose" option to the config file - add "verobse=true" to your config to see lots of debugging info!
- Automatic discovery of your public key
What's new in 3.0.13
- Bugfix in retreval code
- More debugging information in the FEC stuff
What's new in 3.0.12
- Bugfix in activelink handling for static sites
- Option to skip over the local node when inserting content
- Verification that content is actully on the network
- Refreshing based on wether we can retrieve content or not
- Support for description.txt on static edition sites
What's new in 3.0.11
- Bug in activelinks on static edition sites
What's new in 3.0.11
- Funcionally the same as v3.0.10, but one of the files got corrupted, so I rebuilt it. Hopefully no-one downloaded the corrupted one....
What's new in 3.0.10
- Two FEC bugs fixed - thanks to GJ and Jaksio
- Errors in readme - thanks to 505a501102
What's new in 3.0.9
- More unified architecture in preperation for hooking up to the GUI - single executable
- DBR sites were broken in 3.0.8 - I copied some code from GJ that uppercased my hex.... weird thing is, I *tested* fishland, and it retrieved for several days with this bug. And then it just stopped working. What the fuck?!
- Default FEC is GJ's new FCP based interface again. Dropped support for old style FEC files.
- Manifest based editions, static based DBRs
What's new in 3.0.8
- Okay, okay, sorry, edition sites didn't work since v3.0.5 due to a typo on my part - or rather, they worked if you typed "SSK@url/edition/index.html", but not if you did "SSK@url/edition".... my bad!
What's new in 3.0.7
- Typo which stopped Fishinsert from working in the SSK keyspace - oops!
What's new in 3.0.6
- yesMyKeyIsReallyReallyReallyCorrectBitch feature especially for negative creep
- FEC is set to version 1.0 by default in the sample config files - oops
- Win32 version split into three seperate packages
- README -> readme.txt
What's new in 3.0.5
- Support for GJ's new FEC format (using FCP calls for now... native code later). Thanks to GJ for the code to steal :)
- Support for changing the edition seperator
What's new in 3.0.4
- Stupid bug with DBR sites with mainfests of >32k - quickly found, since fishland is that site ^_^. Brown paper bag bug, non? :)
- Allow changing of the FCP host/port in the config file
- changed the FEC algorythm to not create more than 256 blocks - thanks to GJ for pointing that out (indirectly). Large FEC files should workish now... maybe
What's new in 3.0.3
- Tool to insert individual files into freenet
- FEC inserts are threaded
- Locking issue making DBR inserts slower than nessesary
- Automatically add PAgM to the end of keys where it is omitted
- Config files *actully work* now ^_^.
- Changed default HTL to 15 (it was 50. I was feeling espteric, okay? :-p)
- Insert keys <32k without redirects - this should make fishsite editions almost as "key friendly" as traditional ones, heh. Not quite tho :-p.
- Free the FEC pointers - oops :)
What's new in 3.0.2
- Bugfixes for edition updating (miscalculation of time based update)
- Bugfixes for the FEC module (memory leak)
What's new in v3.0.1
- special support for edition activelinks
- edition DBR's now work
What's new in v3.0
- Editions
- Bugfixes
- Windows port
Future Vision
What's coming in v3.1
- GUI for configuring - it's coming, really!
msg06292/pgp00000.pgp
Description: PGP signature
