Package cu.ftpd.modules.zipscript.internal

Source Code of cu.ftpd.modules.zipscript.internal.CuftpdZipscript

/**
* Copyright (c) 2007, Markus Jevring <markus@jevring.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The names of the contributors may not be used to endorse or promote
*    products derived from this software without specific prior written
*    permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/

package cu.ftpd.modules.zipscript.internal;

import cu.ftpd.Connection;
import cu.ftpd.Server;
import cu.ftpd.filesystem.filters.SfvFileFilter;
import cu.ftpd.logging.Logging;
import cu.ftpd.modules.zipscript.Zipscript;
import cu.ftpd.user.User;
import cu.shell.ProcessResult;

import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* @author Markus Jevring <markus@jevring.net>
* @since 2007-aug-20 - 21:19:47
* @version $Id: CuftpdZipscript.java 292 2009-03-04 19:44:36Z jevring $
*/
public class CuftpdZipscript implements Zipscript {
    private final Map<String, Race> races = Collections.synchronizedMap(new HashMap<String, Race>());
    private final RaceFormatter raceFormatter;
    private final SfvFileFilter sfvFileFilter = new SfvFileFilter();
    private final RaceLog log;
    private final String[] zipscriptFiles;
    private final String siteShortName;

    public CuftpdZipscript(String zipscriptFilenamePatterns, File raceFormatterTemplate, String siteShortName) {
        this.siteShortName = siteShortName;
        raceFormatter = new RaceFormatter(raceFormatterTemplate);
        if (zipscriptFilenamePatterns != null) {
            zipscriptFiles = zipscriptFilenamePatterns.split(" ");
            for (int i = 0; i < zipscriptFiles.length; i++) {
                zipscriptFiles[i] = zipscriptFiles[i].replace(".","\\.").replace("*",".*").replace("?",".");
            }
        } else {
            zipscriptFiles = null;
        }
        log = new RaceLog();
        Server.getInstance().getTimer().schedule(new RaceExpirationTask(this), 60*1000, 60*1000);
    }

    public boolean isZipscriptFile(String filename) {
        if (zipscriptFiles == null) {
            return false;
        } else {
            for (int i = 0; i < zipscriptFiles.length; i++) {
                String zipscriptFile = zipscriptFiles[i];
                //System.err.println("trying to match " + filename + " against " + zipscriptFile);
                if (filename.matches(zipscriptFile)) {
                    //System.out.println(filename + " matches the zipscript file pattern " + zipscriptFile);
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * Rescan re-checks the integrity of the files according to the sfv-file in the directory.
     * Maybe throw an IOException if the sfv-file wasn't found, or just a FileNotFoundException.
     * Currently no idea how the rescan would feed back from an external zipscript to the client, but our internal zipscript can just use a connection.
     * @param dir the directory to be rescanned.
     * @param sectionName the section in which the event took place
     * @param user the user who initiated the scan
     * @param connection the connection of the scanning user
     * @param rescanParameters the parameters sent to "site rescan"
     */
    public void rescan(String dir, String sectionName, User user, Connection connection, String rescanParameters) {
        // Note: this will create a race for this directory, even if we do not use the cuftpd zipscript, IF there is an sfv-file
        Race race = getRaceForDir(new File(dir), sectionName);
        // wow, rescan is really this fast.
        if (race != null) { // this will be != null if there is any chance of this dir being a race. It will be restored and ready.
            // _todo: should we be able to use cuftpd rescan even if there isn't a race (probably yes)
            // we already can
            connection.respond("200- rescanning, please wait...");
            race.rescan();
            String message = raceFormatter.format(race);
            storeDotMessageForDir(new File(dir), message);
            connection.reply(200, message, true);
            connection.respond("200 rescan ok.");
        } else {
            connection.respond("500 sfv-file not found");
        }
    }

    public ProcessResult process(File file, long checksum, long bytesTransferred, long transferTime, User user, String sectionName, long speed) {
        String filePath = file.getPath();
        //long start = System.currentTimeMillis();
        Race race;
        boolean ok;
        if (isZipscriptFile(file.getName())) {
            if (filePath.endsWith(".sfv")) {
                // create a new race
                race = new Race(filePath, sectionName, siteShortName);
                races.put(race.getName(), race);
                race.setLog(log);
                log.newSfv(file.getName(), race, user);
                race.start();
                ok = true;
            } else {
                File dir = file.getParentFile();
                race = races.get(dir.getName());
                if (race != null) {
                    // this file is part of a race. check it.
                    // if the race came out of the HashMap, then it already has a log set.
                    ok = race.newFile(file, user, checksum, bytesTransferred, transferTime);
                } else {
                    // check if the dir contains an sfv-file. if it does, create a new race for that sfv file
                    race = getRaceForDir(file.getParentFile(), sectionName);
                    if (race != null) {
                        ok = race.newFile(file, user, checksum, bytesTransferred, transferTime);
                        race.start(); // here we want to invoke start after the race has begun,to stop us from handing the recent file twice
                    } else {
                        // this means that there was no sfv file or .raceinfo file in this directory, it's not a race dir, return ok
                        return ProcessResult.OK;
                    }
                }
            }
            String raceMessage = null;
            if (race.getNumerOfCurrentFiles() > 0) {
                raceMessage = raceFormatter.format(race);
                storeDotMessageForDir(file.getParentFile(), raceMessage);
            }
            //System.out.println("EVENT postCheck took " + (System.currentTimeMillis() - start) + " milliseconds");
            if (ok) {
                return new ProcessResult(0, raceMessage);
            } else {
                return ProcessResult.FAILURE;
            }
        } else {
            // this isn't a filetype that the zipscript is supposed to handle anyway
            return ProcessResult.OK;
        }
    }

    /**
     * For external zipscripts, this should probably trigger the postdel (/bin/postdel) script
     *
     * @param file the file that was deleted.
     * @param user the user that deleted the file.
     * @param sectionName the name of the section.
     */
    public void delete(File file, User user, String sectionName) {
        if (!isZipscriptFile(file.getName())) return;
        File dir = file.getParentFile();
        Race race = races.get(dir.getName());
        if (race != null) {
            // this file is part of a race. check it.
            // if the race came out of the HashMap, then it already has a log set.
            race.deleteFile(file, user);
        } else {
            // check if the dir contains an sfv-file. if it does, create a new race for that sfv file
            race = getRaceForDir(dir, sectionName);
            if (race != null) {
                race.deleteFile(file, user);
            }
        }
    }

    private synchronized void storeDotMessageForDir(File dir, String raceMessage) {
        // _todo: for integrity, we should probably serialize the race as well and put it in disk here (and rename this method to store()). If we do, we can consider this as not using memory for restart.
        // this is already done inside the race
        PrintWriter out = null;
        try {
            out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(dir,".message")), "ISO-8859-1")));
            out.print(raceMessage + "\r\n");
            out.flush();
        } catch (FileNotFoundException e) {
            Logging.getErrorLog().reportError("Failed to write .message file for dir " + dir.getPath());
        } catch (UnsupportedEncodingException e) {
            // do nothing, this encoding is supported in all versions of Java, as per the standard
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    private Race getRaceForDir(File racedir, String section) {
        Race race = null;
        File raceinfo = new File(racedir, ".raceinfo");
        // this should only return one file
        if (raceinfo.exists()) {
            // de-serialize
            ObjectInputStream ois = null;
            try {
                //long start = System.currentTimeMillis();
                ois = new ObjectInputStream(new FileInputStream(raceinfo));
                race = (Race)ois.readObject();
                //System.err.println("took " + (System.currentTimeMillis() - start) + " milliseconds to de-serialize race object");
                // if we fail to read, we just keep looking for the .sfv to do it "the old-fashioned way"
            } catch (IOException e) { // this is fine, we'll catch it with the normal creation below
            } catch (ClassNotFoundException e) { // this happens when we try to restore data from old race-files. It's not a problem, since we'll get it on the re-create below. Besides, it should rarely happen.
            } finally {
                if (ois != null){
                    try {
                        ois.close();
                    } catch (IOException e) {
                        // we don't care
                    }
                }
            }
        }
        if (race == null) {
            // failsafe for when the deseriazation fails.
            File[] sfv = racedir.listFiles(sfvFileFilter);
            if (sfv != null && sfv.length == 1) {
                race = new Race(sfv[0].getPath(), section, siteShortName);
                races.put(race.getName(), race);
            }
        }
        if (race != null) {
            races.put(race.getName(), race);
            race.setLog(log);
        }
        return race;
    }

    public void expungeOldRaces() {
        final long now = System.currentTimeMillis();
        synchronized (races) {
            Iterator<Race> i = races.values().iterator();
            while (i.hasNext()) {
                Race race = i.next();
                if ((now - race.getLastUpdated()) > 300 * 1000) { // races that have gone 5 minutes without activity get expunged from memory
                    // if the race has been old for more than 30 minutes, discard it from memory.
                    //System.err.println("expunging race: " + race.getName());
                    i.remove();
                }
            }
        }
    }
}
TOP

Related Classes of cu.ftpd.modules.zipscript.internal.CuftpdZipscript

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.