This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

Deleted File Keeps Coming Back

Help for those learning Tcl or writing their own scripts.
Post Reply
L
Landslyde
Halfop
Posts: 46
Joined: Thu May 01, 2014 6:01 pm

Deleted File Keeps Coming Back

Post by Landslyde »

One of my bots (1.6.21) uses a statistics script that generates a file, tracking how much the users yack on the channel. I have a cron job that deletes this file daily (verified deletion). But, even though the file gets deleted, it keeps showing the old data as if it was never deleted.

My Cron:

Code: Select all

00 03 * * * rm  /home/shianne/eggdrop/scripts/dbase/statistics
What can I do to make my bot clear out the stats of this deleted file statistics? I've tried rehashing to no avail. And if I restart it, the deleted file is back!

This is silly stuff, something so simple as this, but I can't make it work. Any ideas? Anyone?
w
willyw
Revered One
Posts: 1197
Joined: Thu Jan 15, 2009 12:55 am

Re: Deleted File Keeps Coming Back

Post by willyw »

Landslyde wrote: ....
it keeps showing the old data as if it was never deleted.
What do you mean by, "showing" ?
For example: The bot posts the data to a channel at specific times?
...
And if I restart it, the deleted file is back!
After deletion, and immediately after a restart, is there data in this file?
...
Any ideas? Anyone?
Without seeing the complete script, I'll guess that there is code in it that upon rehash and/or restart - checks to see if file exists, and if not then it creates it. If it has data in it, then it creates it just before the .restart.


I suggest that you post the complete script.
For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia !
L
Landslyde
Halfop
Posts: 46
Joined: Thu May 01, 2014 6:01 pm

Post by Landslyde »

My cron job:

Code: Select all

00 03 * * * rm  /home/shianne/eggdrop/scripts/dbase/statistics
This works fine.

Here's the restart.tcl. This works fine.

Code: Select all

## this equals 04:00 am CST
bind cron - {00 03 * * *} restart:cron 

proc restart:cron {min hour day month weekday} { 
   restart
}
The bot restarts at the same time the file is deleted. And when she co,es back, the statistic data from the deleted file is still there. This is very frustrating. Very.
What do you mean by, "showing" ?
For example: The bot posts the data to a channel at specific times?
You manually call up the data, at any time, using commands.
After deletion, and immediately after a restart, is there data in this file?
Yes. It's like the contents of the deleted file are still in the bot's memory, even after a restart. And mysteriously, the file is back. Just as if it had never been deleted.
Without seeing the complete script, I'll guess that there is code in it that upon rehash and/or restart - checks to see if file exists, and if not then it creates it. If it has data in it, then it creates it just before the .restart.

Code: Select all

# Statistics.tcl (C) 2004 perpleXa
#  type ".chanset <chan> +stat" on the partyline to ativate the script for a specific channel.
#  commands: $stat <nick> - shows information about you or a nick. (works only for other nicks when you are op on a channel)
#            $top10 <smilies|words|lines|letters> - shows the top10 chatters, default option is words
#            $top20 <smilies|words|lines|letters> - same as $top10 but with places 11-20


namespace eval statistics {
# Storage file
  variable storage {scripts/dbase/statistics}

# Kill unused entries after x days
  variable killafter 30

# Command trigger
  variable trigger {.}

# smiley regex (only touch this, if you really know, what you are doing!)
  variable smileyregex {(:|8|;|=)(-|o)?(>|<|D|O|o|\)|\(|\]|\[|P|p|\||\\|/)}

  bind PUB   -|-  ${trigger}stats   [namespace current]::spew
  bind PUB   -|-  ${trigger}top10   [namespace current]::toplist
  bind PUB   -|-  ${trigger}top20   [namespace current]::toplist
  bind PUBM  -|-  *                 [namespace current]::monitor
  bind CTCP  -|-  ACTION            [namespace current]::ctcp
  bind EVNT  -|-  save              [namespace current]::save
  bind TIME  -|-  {00 * * * *}      [namespace current]::cleanupdb

  setudef flag stat

  namespace export spew top10 toplist save load monitor
}

proc statistics::ctcp {nickname hostname handle target keyword arguments} {
  if {[validchan $target]} {
    monitor $nickname $hostname $handle $target $arguments
  }
  return 0
}

proc statistics::monitor {nickname hostname handle channel arguments} {
  variable data
  
variable smileyregex
  if {$nickname == "maricar"} { return 0 }
  if {$nickname == "Stryker"} { return 0 }
  if {$nickname == "Cyell"} { return 0 }
  if {([isbotnick $nickname]) || (![channel get $channel stat])} {
    return 0
  }
  set hostname [maskhost *!$hostname]
  regsub -all -- {\002|\003[\d]{0,2}(,[\d]{0,2})?|\006|\007|\017|\026|\037|\n|\t} $arguments {} arguments
  set added(words) [regexp -all -- {\S+} $arguments]
  set added(letters) [regexp -all -- {\S} $arguments]
  if {[string length $smileyregex] >= 1} {
    set added(smilies) [regexp -all -- $smileyregex $arguments]
  } else {
    set added(smilies) 0
  }
  if {(![info exists data($channel,$hostname)])} {
    set data($channel,$hostname) "0 0 0 0 0 NULL"
  }
  regexp -- {^(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\S+)$} $data($channel,$hostname) -> lastseen lines words letters smilies lastnick
  incr lines 1
  incr words $added(words)
  incr letters $added(letters)
  incr smilies $added(smilies)
  set data($channel,$hostname) "[unixtime] $lines $words $letters $smilies $nickname"
}

proc statistics::spew {nickname hostname handle channel arguments} {
  variable data
  if {(![channel get $channel stat])} {
    return 0
  }
  if {([string length $arguments] >= 1)} {
    set target [lindex [clean $arguments] 0]
  } else {
    set target $nickname
  }
  if {![onchan $target $channel]} {
    putserv "PRIVMSG $channel :\[Statistics - Unknown user \002$target\002\]"
    return 0
  }
  set targethost [maskhost *![getchanhost $target $channel]]

  if {[info exists data($channel,$targethost)]} {
    regexp -- {^(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\S+)$} $data($channel,$targethost) -> lastseen lines words letters smilies lastnick
    set wpl [round [expr ($words / $lines.)]]
    set spl [round [expr ($smilies / $lines.)]]
    set lpw [round [expr ($letters / $words.)]]
    putserv "PRIVMSG $channel :\[Statistics - \002$target\002 has written \002$lines\002 lines, \002$words\002 ($wpl per line) words and \002$letters\002 ($lpw per word) letters, containing \002$smilies\002 ($spl per line) smilies\]"
  } else {
    putserv "PRIVMSG $channel :\[Statistics - No valuable information available for \002$target\002\]"
  }
}

proc statistics::top {channel number {type ""}} {
  variable data
  set statistics {}
  switch $type {
    {lines} {set index 1}
    {letters} {set index 3}
    {smilies} {set index 4}
    {default} {set index 2 ; set type "words"}
  }
  foreach {user stats} [array get data $channel,*] {
    set stats [clean $stats]
    lappend statistics "[lindex [clean $stats] 5] [lindex $stats $index]"
  }
  set statistics [lrange [lsort -integer -decreasing -index 1 [lsort -unique -index 0 [lsort -integer -increasing -index 1 $statistics]]] [expr $number - 10] [expr $number - 1]]
  if {$statistics == ""} {
    return "\[Top$number $type - No valuable information available for \002$channel\002\]"
  }
  set output "\[Top$number $type -"
  for {set i 0} {$i < [llength $statistics]} {incr i 1} {
    set item [lindex $statistics $i]
    append output "\x20[expr $i+$number-9]: \002[join [lindex [clean $item] 0] { }]\002 ([lindex $item 1])"
  }
  append output "\]"
  return $output
}

proc statistics::toplist {nickname hostname handle channel arguments} {
  global lastbind
  if {(![channel get $channel stat])} {
    return 0
  }
  set arguments [clean $arguments]
  set key [lindex $arguments 0]
  if {![regexp -- {^.*?([0-9]+)$} $lastbind -> number]} {
    return 0
  }
  if {![regexp -nocase -- {^(words|letters|smilies|lines|)$} $key]} {
    putserv "PRIVMSG $channel :\[Statistics - Unknown option: \002$key\002, valid options are \002letters\002, \002lines\002, \002smilies\002 and \002words\002\]"
    return 0
  }
  putserv "PRIVMSG $channel :[top $channel $number [string tolower $key]]"
}

proc statistics::cleanupdb {args} {
  variable killafter
  variable data
  set killed 0
  foreach {item} [array names data] {
    set lastseen [lindex [clean $data($item)] 0]
    set expire [expr 60 * 60 * 24 * $killafter]
    if {[expr [unixtime] - $lastseen] >= $expire} {
      incr killed
      unset data($item)
    }
  }
  return $killed
}

proc statistics::load {} {
  variable data
  variable storage
  regexp -- {^(\S+/)?.*$} $storage -> directory
  if {[string length $directory] >= 1} {
    if {![file isdirectory $directory]} {
      file mkdir $directory
    }
  }
  if {![file exists $storage]} {
    return 0
  }
  if {[array exists data]} {
    array unset data
  }
  set file [open $storage r]
  while {![eof $file]} {
    gets $file line
    if {[regexp -nocase -- {^channel:(\S+)\sid:(\S+)\svalue:(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\d+)\s(\S+)$} $line -> channel hostname lastseen lines words letters smilies lastnick]} {
      set data($channel,$hostname) "$lastseen $lines $words $letters $smilies $lastnick"
    }
  }
  close $file
}

proc statistics::save {args} {
  variable data
  variable storage
  set file [open $storage w]
  foreach chan_user [array names data] {
    regexp {^(\S+),(\S+)$} $chan_user -> channel user
    puts $file "channel:$channel id:$user value:$data($chan_user)"
  }
  close $file
}

proc statistics::clean {i} {
  regsub -all -- \\\\ $i \\\\\\\\ i
  regsub -all -- \\\[ $i \\\\\[ i
  regsub -all -- \\\] $i \\\\\] i
  regsub -all -- \\\} $i \\\\\} i
  regsub -all -- \\\{ $i \\\\\{ i
  return $i
}

proc statistics::round {num} {
  if {![string match "*.*" $num]} {
    return $num\.0
  }
  if {![regexp -- {^(\d+?)\.(\d+)$} $num -> primary secondary]} {
    error "syntax error in expression '$num'"
  }
  set secondary [expr round([string index $secondary 0].[string range $secondary 1 end])]
  return [expr {($secondary == 10) ? ($primary+1.0) : "$primary.$secondary"}]
}

statistics::load

putlog "Script loaded: Statistics by perpleXa"
w
willyw
Revered One
Posts: 1197
Joined: Thu Jan 15, 2009 12:55 am

Post by willyw »

Landslyde wrote: ...
It's like the contents of the deleted file are still in the bot's memory,
Exactly.
even after a restart.
Or ... stored in a file and read back into memory, on restart? :)


Ok... let's see...

See that line, second from the end of the script?

Code: Select all

statistics::load
that line runs a procedure named
load
found in your script's namespace named "statistics" , every time this script is loaded. That means : every start up, every rehash and every restart

So let's go see what that proc does.

Found this? : proc statistics::load {} {
see those lines like :
set file [open $storage r]
and
close $file
?
That's open and closing a file, and there are lines in between that read that file, and store it in an array named
data

The variable name "data" is used throughout the script ... looks like that is where all the stats are stored.

Now we know how and why the stats are loaded into memory.
They come from a file where they are stored, and it is read in on every start up, or rehash, or .restart
Make sense so far?

Next, let's look at:

Code: Select all

bind EVNT  -|-  save              [namespace current]::save
( go here : http://www.eggheads.org/support/egghtml ... mands.html
and text search to find
bind evnt
and read about what the
save
event is, and when it is triggered. )

Next, find that proc that is called by the bind EVNT
Find this:
proc statistics::save {args} {

That's going through everything in the array named "data" and saving it to a file.
Apparently this happens every time the userfile is saved. I'm not sure, but I seem to recall that happens automatically every 10 minutes, and also on normal exits of the bot... like if you used .restart or .die .

Can you picture now, what is happening?
It's simply coming right behind your cron job that deletes the file, and re-creating it.... just like you described.

I see you have already worked with
bind cron
in your experiments with restart, so you are familiar with it.
If you set a bind cron to trigger at the same time as your cron job that deletes the file, and in this bind cron you have it
unset data
wouldn't you now have: no longer any file that is storing the stats, and no stats in memory?
For a fun (and popular) Trivia game, visit us at: irc.librairc.net #science-fiction . Over 300K Q & A to play in BogusTrivia !
Post Reply