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.

flood check

Help for those learning Tcl or writing their own scripts.
Post Reply
t
tmyoungjr
Voice
Posts: 14
Joined: Fri Aug 24, 2007 3:30 pm

flood check

Post by tmyoungjr »

I have a real simple script that i found here in the forums :

Code: Select all

bind pub - !fact pub_fact

proc pub_fact {n u h c t} {
  set fl [open fact.txt] 
  set data [read $fl]
  close $fl
  set lines [split $data \n]
  set randline [lindex $lines [rand [llength $lines]]]
  putserv "privmsg $c $randline"
}
i'll modify it a bit for my needs. what i'm looking for tho is flood control. i want to limit the # of times this script will return anything (something like say 1 request every minute or some such). i've found many scripts with flood control built in, but they all seem excessively complicated for my needs. any assistance would be great.
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

bind pub - !fact pub_fact

proc pub_fact {n u h c t} {
global varTimer
if {![info exists varTimer]} {
set varTimer 1
utimer 60 [unset varTimer]
set fl [open fact.txt]
set data [read $fl]
close $fl
set lines [split $data \n]
set randline [lindex $lines [rand [llength $lines]]]
putserv "privmsg $c :$randline"
}
return 0
}
t
tmyoungjr
Voice
Posts: 14
Joined: Fri Aug 24, 2007 3:30 pm

Post by tmyoungjr »

thank you - this works wonderfully
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

I know you said the above worked but recent coding I have done on something unrelated has caused me to rethink the solution I provided, as a generic means of preventing flood. I found the solution below to be more reliable.

Code: Select all

bind pub - !fact pub_fact 

proc pub_fact {n u h c t} { 
  unbind pub - !fact pub_fact
  set fl [open fact.txt] 
  set data [read $fl] 
  close $fl 
  set lines [split $data \n] 
  set randline [lindex $lines [rand [llength $lines]]] 
  putserv "privmsg $c :$randline" 
  utimer 60 [list bind pub - !fact pub_fact]
  return 0 
}
User avatar
TCL_no_TK
Owner
Posts: 509
Joined: Fri Aug 25, 2006 7:05 pm
Location: England, Yorkshire

Post by TCL_no_TK »

Code: Select all

  set fl [open fact.txt] 
  set data [read $fl]
Replace with

Code: Select all

  set fs [file size "fact.txt"]
  set fl [open fact.txt] 
  set data [read $fl $fs]
:wink:
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

TCL_no_TK:
What would the purpose of such a modification be?

Also, the extended syntax of read specifies the number of characters to read, while file size returns the number of bytes. Which certain charsets, such as UTF-8, one character may consist of several bytes. You will get away with this, as read, for normal files, reads as much as "numChars" charaters, or up until EOF, which ever comes first. Should the channelId however have been a serial port, the read command would block until the specific amount of characters have been recieved (of course, file size would not be useful on a serial port in the first place).

The point being, there is no good reason for specifying the number of characters to read, should you desire to read the whole file.
NML_375
User avatar
TCL_no_TK
Owner
Posts: 509
Joined: Fri Aug 25, 2006 7:05 pm
Location: England, Yorkshire

Post by TCL_no_TK »

Performance :!:
:arrow:
... there is one trick that might be necessary. Determine the size of the file first, then 'read' that many bytes. This allows the channel code to optimize buffer handling (preallocation in the correct size). I don't know anymore who posted this first. But you only need this for Tcl 8.0. This is something for the Tcl Performance page as well.
from How do I read and write files in Tcl
n
nml375
Revered One
Posts: 2860
Joined: Fri Aug 04, 2006 2:09 pm

Post by nml375 »

That performance-issue would be restricted to Tcl 8.0, and would still be flawed with the byte vs char issue...
In any case, I fail to see how that is related to the topic.

@tmyoungjr:
I believe user posted a very flexible throttling-mechanism that could easily be adopted to your script.
Check this post: http://forum.egghelp.org/viewtopic.php?p=75097#75097

arfer's approach is interresting, yet may cause the script to stop responding should any I/O-errors occur during the reading. Would probably be a good idea to move the utimer to the top of the proc.
Also worth mentioning, is that this will keep resetting the bind-counter every time it triggers.

A third option would be to simply use timestamps, removing the need for any timers or cleanup. Example posted below:

Code: Select all

proc throttle {id time} {
 if {[info exists ::throttle($id)] && $::throttle($id) > [clock seconds]} {
  return 0
 }
 set ::throttle($id) [expr [clock seconds] + $time]
 return 1
}

proc myproc {} {
 if {[throttle "theid" 60]} {
  #we're ok, do the good stuff here
 } {
  #still throttle'd, do nothing
  return 0
 }
}
NML_375
Post Reply