001: /*
002: * This file is part of DrFTPD, Distributed FTP Daemon.
003: *
004: * DrFTPD is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * DrFTPD is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with DrFTPD; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package org.drftpd.plugins;
019:
020: import java.io.FileNotFoundException;
021: import java.io.FileWriter;
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.net.UnknownHostException;
025: import java.text.DateFormat;
026: import java.text.SimpleDateFormat;
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.Collections;
030: import java.util.Date;
031: import java.util.Iterator;
032: import java.util.Locale;
033:
034: import net.sf.drftpd.FatalException;
035: import net.sf.drftpd.NoAvailableSlaveException;
036: import net.sf.drftpd.Nukee;
037: import net.sf.drftpd.SlaveUnavailableException;
038: import net.sf.drftpd.event.DirectoryFtpEvent;
039: import net.sf.drftpd.event.Event;
040: import net.sf.drftpd.event.FtpListener;
041: import net.sf.drftpd.event.InviteEvent;
042: import net.sf.drftpd.event.MessageEvent;
043: import net.sf.drftpd.event.NukeEvent;
044: import net.sf.drftpd.event.SlaveEvent;
045: import net.sf.drftpd.event.TransferEvent;
046: import net.sf.drftpd.master.GroupPosition;
047: import net.sf.drftpd.master.UploaderPosition;
048:
049: import org.apache.log4j.Level;
050: import org.apache.log4j.Logger;
051: import org.drftpd.SFVFile;
052: import org.drftpd.SFVFile.SFVStatus;
053: import org.drftpd.commands.Nuke;
054: import org.drftpd.commands.UserManagement;
055: import org.drftpd.remotefile.FileStillTransferringException;
056: import org.drftpd.remotefile.LinkedRemoteFileInterface;
057: import org.drftpd.slave.SlaveStatus;
058: import org.drftpd.usermanager.NoSuchUserException;
059: import org.drftpd.usermanager.User;
060: import org.drftpd.usermanager.UserFileException;
061: import org.tanesha.replacer.FormatterException;
062:
063: /**
064: * @author flowman
065: * @version $Id: GlftpdLog.java 1513 2006-10-13 22:41:08Z tdsoul $
066: */
067: public class GlftpdLog extends FtpListener {
068: private static Logger logger = Logger.getLogger(GlftpdLog.class);
069:
070: private PrintWriter _out;
071: DateFormat DATE_FMT = new SimpleDateFormat(
072: "EEE MMM d HH:mm:ss yyyy ", Locale.ENGLISH);
073:
074: public GlftpdLog() throws UnknownHostException, IOException {
075: _out = new PrintWriter(new FileWriter("logs/glftpd.log"));
076: }
077:
078: public void actionPerformed(Event event) {
079: try {
080: if (event instanceof DirectoryFtpEvent) {
081: actionPerformedDirectory((DirectoryFtpEvent) event);
082: } else if (event instanceof NukeEvent) {
083: actionPerformedNuke((NukeEvent) event);
084: } else if (event instanceof SlaveEvent) {
085: actionPerformedSlave((SlaveEvent) event);
086: } else if (event instanceof InviteEvent) {
087: actionPerformedInvite((InviteEvent) event);
088: } else if (event.getCommand().equals("SHUTDOWN")) {
089: MessageEvent mevent = (MessageEvent) event;
090: print("SHUTDOWN: \"" + mevent.getMessage() + "\"");
091: }
092: } catch (FormatterException ex) {
093: }
094: }
095:
096: private void actionPerformedDirectory(DirectoryFtpEvent direvent)
097: throws FormatterException {
098: if ("MKD".equals(direvent.getCommand())) {
099: sayDirectorySection(direvent, "NEWDIR", direvent
100: .getDirectory());
101: } else if ("REQUEST".equals(direvent.getCommand())) {
102: sayDirectorySection(direvent, "REQUEST", direvent
103: .getDirectory());
104: } else if ("REQFILLED".equals(direvent.getCommand())) {
105: sayDirectorySection(direvent, "REQFILLED", direvent
106: .getDirectory());
107: } else if ("RMD".equals(direvent.getCommand())) {
108: sayDirectorySection(direvent, "DELDIR", direvent
109: .getDirectory());
110: } else if ("WIPE".equals(direvent.getCommand())) {
111: if (direvent.getDirectory().isDirectory()) {
112: sayDirectorySection(direvent, "WIPE", direvent
113: .getDirectory());
114: }
115: } else if ("PRE".equals(direvent.getCommand())) {
116: sayDirectorySection(direvent, "PRE", direvent
117: .getDirectory());
118: } else if (direvent.getCommand().equals("STOR")) {
119: actionPerformedDirectorySTOR((TransferEvent) direvent);
120: } else {
121: // Unhandled DirectoryEvent:
122: }
123: }
124:
125: private void sayDirectorySection(DirectoryFtpEvent direvent,
126: String string, LinkedRemoteFileInterface dir)
127: throws FormatterException {
128: // TYPE = NEWDIR, DELDIR, WIPE, etc.
129: // TYPE: "/path/to/release" "username" "group" "tagline"
130: print(""
131: + string
132: + ": \""
133: + dir.getPath()
134: + "\" \""
135: + direvent.getUser().getName()
136: + "\" \""
137: + direvent.getUser().getGroup()
138: + "\" \""
139: + direvent.getUser().getKeyedMap().getObjectString(
140: UserManagement.TAGLINE) + "\"");
141: }
142:
143: private void actionPerformedDirectorySTOR(TransferEvent direvent)
144: throws FormatterException {
145:
146: LinkedRemoteFileInterface dir;
147:
148: try {
149: dir = direvent.getDirectory().getParentFile();
150: } catch (FileNotFoundException e) {
151: throw new FatalException(e);
152: }
153:
154: SFVFile sfvfile;
155:
156: try {
157: sfvfile = dir.lookupSFVFile();
158:
159: // throws IOException, ObjectNotFoundException, NoAvailableSlaveException
160: } catch (FileNotFoundException ex) {
161: // No sfv file in in dir
162: return;
163: } catch (NoAvailableSlaveException e) {
164: // No available slave with .sfv
165: return;
166: } catch (IOException e) {
167: // IO error reading .sfv
168: return;
169: } catch (FileStillTransferringException e) {
170: // SFVFile still being uploaded
171: return;
172: }
173:
174: long starttime = Long.MAX_VALUE;
175:
176: for (Iterator iter = sfvfile.getFiles().iterator(); iter
177: .hasNext();) {
178: LinkedRemoteFileInterface file = (LinkedRemoteFileInterface) iter
179: .next();
180:
181: if (file.lastModified() < starttime) {
182: starttime = file.lastModified();
183: }
184: }
185:
186: if (!sfvfile.hasFile(direvent.getDirectory().getName())) {
187: return;
188: }
189:
190: int halfway = (int) Math.floor((double) sfvfile.size() / 2);
191:
192: ///// start ///// start ////
193: //check if new racer
194: String username = direvent.getUser().getName();
195: SFVStatus sfvstatus = sfvfile.getStatus();
196:
197: if ((sfvfile.size() - sfvstatus.getMissing()) != 1) {
198: for (Iterator iter = sfvfile.getFiles().iterator(); iter
199: .hasNext();) {
200: LinkedRemoteFileInterface sfvFileEntry = (LinkedRemoteFileInterface) iter
201: .next();
202:
203: if (sfvFileEntry == direvent.getDirectory()) {
204: continue;
205: }
206:
207: if (sfvFileEntry.getUsername().equals(username)) {
208: break;
209: }
210:
211: if (!iter.hasNext()) {
212: // RACE: "/path/to/release" "new_racer_username" "new_racer_group"
213: // "whois_he_racing" "new_racers_speed" "files_left" "time_raced"
214: print("RACE: \""
215: + dir.getPath()
216: + "\" \""
217: + direvent.getUser().getName()
218: + "\" \""
219: + direvent.getUser().getGroup()
220: + "\" \""
221: + sfvfile.getXferspeed()
222: + "\" \""
223: + Integer.toString(sfvstatus.getMissing())
224: + "\" \""
225: + Long
226: .toString((direvent.getTime() - starttime) / 1000)
227: + "\"");
228: }
229: }
230: }
231:
232: //COMPLETE
233: if (sfvstatus.isFinished()) {
234: Collection racers = SiteBot.userSort(sfvfile.getFiles(),
235: "bytes", "high");
236: Collection groups = topFileGroup(sfvfile.getFiles());
237: Collection fast = SiteBot.userSort(sfvfile.getFiles(),
238: "xferspeed", "high");
239: Collection slow = SiteBot.userSort(sfvfile.getFiles(),
240: "xferspeed", "low");
241:
242: UploaderPosition fastestuser = (UploaderPosition) fast
243: .iterator().next();
244: UploaderPosition slowestuser = (UploaderPosition) slow
245: .iterator().next();
246:
247: User fastuser;
248: User slowuser;
249:
250: try {
251: fastuser = getGlobalContext().getUserManager()
252: .getUserByName(fastestuser.getUsername());
253: slowuser = getGlobalContext().getUserManager()
254: .getUserByName(slowestuser.getUsername());
255: } catch (NoSuchUserException e2) {
256: return;
257: } catch (UserFileException e2) {
258: logger.fatal("Error reading userfile", e2);
259: return;
260: }
261:
262: //COMPLETERACE: "/path/to/release" "release_size" "release_files" "release_avrage_speed"
263: // "release_total_upload_time" "number_of_racers" "number_of_racing_groups"
264: // "fastest_uploader_username" "fastest_uploader_group" "fastest_uploaders_speed"
265: // "slowest_uploader_username" "slowest_uploader_group" "slowest_uploaders_speed"
266: print("COMPLETE: \""
267: + dir.getPath()
268: + "\" \""
269: + sfvfile.getTotalBytes()
270: + "\" \""
271: + Integer.toString(sfvfile.size())
272: + "\" \""
273: + sfvfile.getXferspeed()
274: + "\" \""
275: + Long
276: .toString((direvent.getTime() - starttime) / 1000)
277: + "\" \"" + Integer.toString(racers.size())
278: + "\" \"" + Integer.toString(groups.size())
279: + "\" \"" + fastuser.getName() + "\" \""
280: + fastuser.getGroup() + "\" \""
281: + fastestuser.getXferspeed() + "\" \""
282: + slowuser.getName() + "\" \""
283: + slowuser.getGroup() + "\" \""
284: + slowestuser.getXferspeed() + "\"");
285:
286: print("STATS: \"" + dir.getPath() + "\" \"UserTop:\"");
287:
288: int position = 1;
289:
290: for (Iterator iter = racers.iterator(); iter.hasNext();) {
291: UploaderPosition stat = (UploaderPosition) iter.next();
292:
293: User raceuser;
294:
295: try {
296: raceuser = getGlobalContext().getUserManager()
297: .getUserByName(stat.getUsername());
298: } catch (NoSuchUserException e2) {
299: continue;
300: } catch (UserFileException e2) {
301: logger.log(Level.FATAL, "Error reading userfile",
302: e2);
303:
304: continue;
305: }
306:
307: // STATSUSER: "/path/to/release" "race_place" "username" "group" "mb_uploaded"
308: // "files_uploaded" "percent_uploaded" "avrage_speed"
309: print("STATSUSER: \""
310: + dir.getPath()
311: + "\" \""
312: + new Integer(position++)
313: + "\" \""
314: + raceuser.getName()
315: + "\" \""
316: + raceuser.getGroup()
317: + "\" \""
318: + stat.getBytes()
319: + "\" \""
320: + Integer.toString(stat.getFiles())
321: + "\" \""
322: + Integer.toString((stat.getFiles() * 100)
323: / sfvfile.size()) + "\" \""
324: + stat.getXferspeed() + "\"");
325: }
326:
327: print("STATS: \"" + dir.getPath() + "\" \"GroupTop:\"");
328:
329: position = 1;
330:
331: for (Iterator iter = groups.iterator(); iter.hasNext();) {
332: GroupPosition stat = (GroupPosition) iter.next();
333:
334: // STATSGROUP: "/path/to/release" "race_place" "group" "mb_uploaded"
335: // "files_uploaded" "percent_uploaded" "avrage_speed"
336: print("STATSGROUP: \""
337: + dir.getPath()
338: + "\" \""
339: + new Integer(position++)
340: + "\" \""
341: + stat.getGroupname()
342: + "\" \""
343: + stat.getBytes()
344: + "\" \""
345: + Integer.toString(stat.getFiles())
346: + "\" \""
347: + Integer.toString((stat.getFiles() * 100)
348: / sfvfile.size()) + "\" \""
349: + stat.getXferspeed() + "\"");
350: }
351:
352: //HALFWAY
353: } else if ((sfvfile.size() >= 4)
354: && (sfvstatus.getMissing() == halfway)) {
355: Collection uploaders = SiteBot.userSort(sfvfile.getFiles(),
356: "bytes", "high");
357: UploaderPosition stat = (UploaderPosition) uploaders
358: .iterator().next();
359:
360: User leaduser;
361:
362: try {
363: leaduser = getGlobalContext().getUserManager()
364: .getUserByName(stat.getUsername());
365: } catch (NoSuchUserException e3) {
366: return;
367: } catch (UserFileException e3) {
368: logger.log(Level.FATAL, "Error reading userfile", e3);
369:
370: return;
371: }
372:
373: // HALFWAY: "/path/to/release" "leading_username" "group" "mb_uploaded"
374: // "files_uploaded" "percent_uploaded" "avrage_speed" "files_left"
375: print("HALFWAY: \""
376: + dir.getPath()
377: + "\" \""
378: + leaduser.getName()
379: + "\" \""
380: + leaduser.getGroup()
381: + "\" \""
382: + stat.getBytes()
383: + "\" \""
384: + Integer.toString(stat.getFiles())
385: + "\" \""
386: + Integer.toString((stat.getFiles() * 100)
387: / sfvfile.size()) + "\" \""
388: + stat.getXferspeed() + "\" \""
389: + Integer.toString(sfvstatus.getMissing()) + "\"");
390: }
391: }
392:
393: private void actionPerformedSlave(SlaveEvent sevent)
394: throws FormatterException {
395: if (sevent.getCommand().equals("ADDSLAVE")) {
396: SlaveStatus status;
397:
398: try {
399: status = sevent.getRSlave().getSlaveStatusAvailable();
400: } catch (SlaveUnavailableException e) {
401: return;
402: }
403:
404: print("SLAVEONLINE: \"" + sevent.getRSlave().getName()
405: + "\" \"" + sevent.getMessage() + "\" \""
406: + status.getDiskSpaceCapacity() + "\" \""
407: + status.getDiskSpaceAvailable() + "\"");
408: } else if (sevent.getCommand().equals("DELSLAVE")) {
409: print("SLAVEOFFLINE: \"" + sevent.getRSlave().getName()
410: + "\"");
411: }
412: }
413:
414: private void actionPerformedInvite(InviteEvent event) {
415: String user = event.getIrcNick();
416: print("INVITE: \"" + user + "\" \"" + event.getUser().getName()
417: + "\" \"" + event.getUser().getGroup() + "\"");
418: }
419:
420: private void actionPerformedNuke(NukeEvent event)
421: throws FormatterException {
422: String cmd = event.getCommand();
423:
424: if (cmd.equals("NUKE")) {
425: print("NUKE: \"" + event.getPath() + "\" \""
426: + event.getUser().getName() + "\" \""
427: + event.getUser().getGroup() + "\" \""
428: + String.valueOf(event.getMultiplier()) + " "
429: + event.getSize() + "\" \"" + event.getReason()
430: + "\"");
431:
432: int position = 1;
433: long nobodyAmount = 0;
434:
435: for (Iterator iter = event.getNukees2().iterator(); iter
436: .hasNext();) {
437: Nukee stat = (Nukee) iter.next();
438:
439: User raceuser;
440:
441: try {
442: raceuser = getGlobalContext().getUserManager()
443: .getUserByName(stat.getUsername());
444: } catch (NoSuchUserException e2) {
445: nobodyAmount += stat.getAmount();
446:
447: continue;
448: } catch (UserFileException e2) {
449: logger.log(Level.FATAL, "Error reading userfile",
450: e2);
451:
452: continue;
453: }
454:
455: long nukedamount = Nuke.calculateNukedAmount(stat
456: .getAmount(), raceuser.getKeyedMap()
457: .getObjectFloat(UserManagement.RATIO), event
458: .getMultiplier());
459:
460: print("NUKEE: \"" + raceuser.getName() + "\" \""
461: + raceuser.getGroup() + "\" \"" + position++
462: + "\" \"" + stat.getAmount() + " "
463: + nukedamount + "\"");
464: }
465:
466: if (nobodyAmount != 0) {
467: print("NUKEE: \"" + "nobody" + "\" \"" + "nogroup"
468: + "\" \"" + "?" + "\" \"" + nobodyAmount + " "
469: + nobodyAmount + "\"");
470: }
471: } else if (cmd.equals("UNNUKE")) {
472: print("UNNUKE: \"" + event.getPath() + "\" \""
473: + event.getUser().getName() + "\" \""
474: + event.getUser().getGroup() + "\" \""
475: + String.valueOf(event.getMultiplier()) + " "
476: + event.getSize() + "\" \"" + event.getReason()
477: + "\"");
478: }
479: }
480:
481: public static Collection topFileGroup(Collection files) {
482: ArrayList<GroupPosition> ret = new ArrayList<GroupPosition>();
483:
484: for (Iterator iter = files.iterator(); iter.hasNext();) {
485: LinkedRemoteFileInterface file = (LinkedRemoteFileInterface) iter
486: .next();
487: String groupname = file.getGroupname();
488:
489: GroupPosition stat = null;
490:
491: for (Iterator iter2 = ret.iterator(); iter2.hasNext();) {
492: GroupPosition stat2 = (GroupPosition) iter2.next();
493:
494: if (stat2.getGroupname().equals(groupname)) {
495: stat = stat2;
496:
497: break;
498: }
499: }
500:
501: if (stat == null) {
502: stat = new GroupPosition(groupname, file.length(), 1,
503: file.getXfertime());
504: ret.add(stat);
505: } else {
506: stat.updateBytes(file.length());
507: stat.updateFiles(1);
508: stat.updateXfertime(file.getXfertime());
509: }
510: }
511:
512: Collections.sort(ret);
513:
514: return ret;
515: }
516:
517: public void print(String line) {
518: print(new Date(), line);
519: }
520:
521: public void print(Date date, String line) {
522: _out.println(DATE_FMT.format(date) + line);
523: _out.flush();
524: }
525:
526: public void unload() {
527: }
528: }
|