Code: Select all
# this would be so usefull (but only possible if vwait would work)
bind join - * joinproc
proc joinproc { nickname hostname handle channel } {
# getting some extra private vars
# set extrainfo [subproc $handle $channel]
# wait until the whois is done.....
after $timeoutsetting.... [list set ::user_info(whois_end,$nickname) 0]
vwait ::user_info(whois_end,$nickname)
if { $::user_info(whois_end,$nickname) == 0 } {
# whois not done......
# processing if no whois done.........
return
}
# the whois is done and we can use all variables we got from whois
# and all previous private variables we got
# processing .....
}
#
#
#
# raw realname
bind raw - 311 raw:311
proc raw:311 { from key text } {
set nickname [lindex [split $text " "] 1]
set realname [lindex [split $text ":"] end]
set ::user_info(real_name,$nickname) $realname
}
# raw authname
bind raw - 330 raw:330
proc raw:330 { from key text } {
set nickname [lindex [split $text " "] 1]
set authname [lindex [split $text " "] 2]
set ::user_info(authname,$nickname) $authname
}
# raw end of whois
bind raw - 318 raw:318
proc raw:318 { from key text } {
set nick_list [lindex [split $text " "] 1]
set nick_list [split $nick_list ","]
foreach nickname $nick_list {
set ::user_info(whois_end,$nickname) 1
whois_done_callback $nickname
}
}
# just example, need many other binds about whois like channels, away and so on
# need bind if whois failed (no such nickname raw reply)
#
#
#
# the current usual/impractically way
proc whois_done_callback { nickname } {
# uhm, well
# don`t know which channel he joined - would need to store this in a global variable aswell too
# but what if he is already parted/offline?
# what if he joined two or more of the bots channels in a short amount of time
# need the hostname of the user --> getchanhost? --> no if he is not longer in chan then this will be return ""
# so we need to store this info aswell too
}
Code: Select all
bind join - * query_userinfo
proc query_userinfo {nick host hand chan text} {
# already waiting for information for that nick? (maybe for another channel, won't solve that for this snippet)
if {[info commands queryinfo_$nick] != ""} { return }
coroutine queryinfo_$nick queryinfo_template $nick $chan
}
proc queryinfo_template {nick chan} {
putserv "WHOIS $nick"
# pause the execution
yield
putserv "PRIVMSG $chan :Hi $nick, your realname is: '$::userinfo_realname($nick)'."
if {[info exists ::userinfo_identification($nick)]} {
putserv "PRIVMSG $chan :$nick, you're identified as '$::userinfo_identification($nick)'"
unset ::userinfo_identification($nick)
}
unset ::userinfo_realname($nick)
}
# raw realname
bind raw - 311 raw:311
proc raw:311 { from key text } {
set realname [join [lassign [split $text] trash nick]]
if {[string index $realname 0] == ":"} {
set realname [string range $realname 1 end]
}
set ::userinfo_realname($nick) $realname
}
# raw authname
bind raw - 330 raw:330
proc raw:330 { from key text } {
lassign [split $text] trash nick login
set ::userinfo_identification($nick) $login
}
# raw end of whois
bind raw - 318 raw:318
proc raw:318 { from key text } {
set nick_list [lindex [split $text] 1]
set nick_list [split $nick_list ","]
foreach nickname $nick_list {
if {[info commands queryinfo_$nick] != ""} {
# continue execution
queryinfo_$nick
}
}
}
Code: Select all
diff -urN eggdrop1.6.19/src/main.c eggdrop1.6.19+vwait/src/main.c
--- eggdrop1.6.19/src/main.c 2008-02-16 22:41:03.000000000 +0100
+++ eggdrop1.6.19+vwait/src/main.c 2009-03-05 19:41:19.000000000 +0100
@@ -129,6 +129,9 @@
int resolve_timeout = 15; /* Hostname/address lookup timeout */
char quit_msg[1024]; /* Quit message */
+int orig_argc = 0;
+char **orig_argv = NULL;
+
/* Traffic stats */
unsigned long otraffic_irc = 0;
unsigned long otraffic_irc_today = 0;
@@ -705,10 +708,186 @@
run_cnt++;
}
+void eventloop() {
+ int xx, i;
+ char buf[520];
+ int socket_cleanup = 0;
+
+#ifdef USE_TCL_EVENTS
+ /* Process a single tcl event */
+ Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
+#endif /* USE_TCL_EVENTS */
+
+ /* Lets move some of this here, reducing the numer of actual
+ * calls to periodic_timers
+ */
+ now = time(NULL);
+ random(); /* Woop, lets really jumble things */
+ if (now != then) { /* Once a second */
+ call_hook(HOOK_SECONDLY);
+ then = now;
+ }
+
+ /* Only do this every so often. */
+ if (!socket_cleanup) {
+ socket_cleanup = 5;
+
+ /* Remove dead dcc entries. */
+ dcc_remove_lost();
+
+ /* Check for server or dcc activity. */
+ dequeue_sockets();
+ } else
+ socket_cleanup--;
+
+ /* Free unused structures. */
+ garbage_collect();
+
+ xx = sockgets(buf, &i);
+ if (xx >= 0) { /* Non-error */
+ int idx;
+
+ for (idx = 0; idx < dcc_total; idx++)
+ if (dcc[idx].sock == xx) {
+ if (dcc[idx].type && dcc[idx].type->activity) {
+ /* Traffic stats */
+ if (dcc[idx].type->name) {
+ if (!strncmp(dcc[idx].type->name, "BOT", 3))
+ itraffic_bn_today += strlen(buf) + 1;
+ else if (!strcmp(dcc[idx].type->name, "SERVER"))
+ itraffic_irc_today += strlen(buf) + 1;
+ else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
+ itraffic_dcc_today += strlen(buf) + 1;
+ else if (!strncmp(dcc[idx].type->name, "FILES", 5))
+ itraffic_dcc_today += strlen(buf) + 1;
+ else if (!strcmp(dcc[idx].type->name, "SEND"))
+ itraffic_trans_today += strlen(buf) + 1;
+ else if (!strncmp(dcc[idx].type->name, "GET", 3))
+ itraffic_trans_today += strlen(buf) + 1;
+ else
+ itraffic_unknown_today += strlen(buf) + 1;
+ }
+ dcc[idx].type->activity(idx, buf, i);
+ } else
+ putlog(LOG_MISC, "*",
+ "!!! untrapped dcc activity: type %s, sock %d",
+ dcc[idx].type->name, dcc[idx].sock);
+ break;
+ }
+ } else if (xx == -1) { /* EOF from someone */
+ int idx;
+
+ if (i == STDOUT && !backgrd)
+ fatal("END OF FILE ON TERMINAL", 0);
+ for (idx = 0; idx < dcc_total; idx++)
+ if (dcc[idx].sock == i) {
+ if (dcc[idx].type && dcc[idx].type->eof)
+ dcc[idx].type->eof(idx);
+ else {
+ putlog(LOG_MISC, "*",
+ "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED",
+ i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*");
+ killsock(i);
+ lostdcc(idx);
+ }
+ idx = dcc_total + 1;
+ }
+ if (idx == dcc_total) {
+ putlog(LOG_MISC, "*",
+ "(@) EOF socket %d, not a dcc socket, not anything.", i);
+ close(i);
+ killsock(i);
+ }
+ } else if (xx == -2 && errno != EINTR) { /* select() error */
+ putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
+ for (i = 0; i < dcc_total; i++) {
+ if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) {
+ putlog(LOG_MISC, "*",
+ "DCC socket %d (type %d, name '%s') expired -- pfft",
+ dcc[i].sock, dcc[i].type, dcc[i].nick);
+ killsock(dcc[i].sock);
+ lostdcc(i);
+ i--;
+ }
+ }
+ } else if (xx == -3) {
+ call_hook(HOOK_IDLE);
+ socket_cleanup = 0; /* If we've been idle, cleanup & flush */
+ }
+
+ if (do_restart) {
+ if (do_restart == -2)
+ rehash();
+ else {
+ /* Unload as many modules as possible */
+ int f = 1;
+ module_entry *p;
+ Function startfunc;
+ char name[256];
+
+ /* oops, I guess we should call this event before tcl is restarted */
+ check_tcl_event("prerestart");
+
+ while (f) {
+ f = 0;
+ for (p = module_list; p != NULL; p = p->next) {
+ dependancy *d = dependancy_list;
+ int ok = 1;
+
+ while (ok && d) {
+ if (d->needed == p)
+ ok = 0;
+ d = d->next;
+ }
+ if (ok) {
+ strcpy(name, p->name);
+ if (module_unload(name, botnetnick) == NULL) {
+ f = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Make sure we don't have any modules left hanging around other than
+ * "eggdrop" and the two that are supposed to be.
+ */
+ for (f = 0, p = module_list; p; p = p->next) {
+ if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") &&
+ strcmp(p->name, "uptime")) {
+ f++;
+ }
+ }
+ if (f != 0) {
+ putlog(LOG_MISC, "*", MOD_STAGNANT);
+ }
+
+ flushlogs();
+ kill_tcl();
+ init_tcl(orig_argc, orig_argv);
+ init_language(0);
+
+ /* this resets our modules which we didn't unload (encryption and uptime) */
+ for (p = module_list; p; p = p->next) {
+ if (p->funcs) {
+ startfunc = p->funcs[MODCALL_START];
+ startfunc(NULL);
+ }
+ }
+
+ rehash();
+ restart_chons();
+ call_hook(HOOK_LOADED);
+ }
+
+ do_restart = 0;
+ }
+}
+
int main(int argc, char **argv)
{
int xx, i;
- char buf[520], s[25];
+ char s[25];
FILE *f;
struct sigaction sv;
struct chanset_t *chan;
@@ -930,178 +1109,11 @@
call_hook(HOOK_LOADED);
+ orig_argc = argc;
+ orig_argv = argv;
+
debug0("main: entering loop");
while (1) {
- int socket_cleanup = 0;
-
-#ifdef USE_TCL_EVENTS
- /* Process a single tcl event */
- Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
-#endif /* USE_TCL_EVENTS */
-
- /* Lets move some of this here, reducing the numer of actual
- * calls to periodic_timers
- */
- now = time(NULL);
- random(); /* Woop, lets really jumble things */
- if (now != then) { /* Once a second */
- call_hook(HOOK_SECONDLY);
- then = now;
- }
-
- /* Only do this every so often. */
- if (!socket_cleanup) {
- socket_cleanup = 5;
-
- /* Remove dead dcc entries. */
- dcc_remove_lost();
-
- /* Check for server or dcc activity. */
- dequeue_sockets();
- } else
- socket_cleanup--;
-
- /* Free unused structures. */
- garbage_collect();
-
- xx = sockgets(buf, &i);
- if (xx >= 0) { /* Non-error */
- int idx;
-
- for (idx = 0; idx < dcc_total; idx++)
- if (dcc[idx].sock == xx) {
- if (dcc[idx].type && dcc[idx].type->activity) {
- /* Traffic stats */
- if (dcc[idx].type->name) {
- if (!strncmp(dcc[idx].type->name, "BOT", 3))
- itraffic_bn_today += strlen(buf) + 1;
- else if (!strcmp(dcc[idx].type->name, "SERVER"))
- itraffic_irc_today += strlen(buf) + 1;
- else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
- itraffic_dcc_today += strlen(buf) + 1;
- else if (!strncmp(dcc[idx].type->name, "FILES", 5))
- itraffic_dcc_today += strlen(buf) + 1;
- else if (!strcmp(dcc[idx].type->name, "SEND"))
- itraffic_trans_today += strlen(buf) + 1;
- else if (!strncmp(dcc[idx].type->name, "GET", 3))
- itraffic_trans_today += strlen(buf) + 1;
- else
- itraffic_unknown_today += strlen(buf) + 1;
- }
- dcc[idx].type->activity(idx, buf, i);
- } else
- putlog(LOG_MISC, "*",
- "!!! untrapped dcc activity: type %s, sock %d",
- dcc[idx].type->name, dcc[idx].sock);
- break;
- }
- } else if (xx == -1) { /* EOF from someone */
- int idx;
-
- if (i == STDOUT && !backgrd)
- fatal("END OF FILE ON TERMINAL", 0);
- for (idx = 0; idx < dcc_total; idx++)
- if (dcc[idx].sock == i) {
- if (dcc[idx].type && dcc[idx].type->eof)
- dcc[idx].type->eof(idx);
- else {
- putlog(LOG_MISC, "*",
- "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED",
- i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*");
- killsock(i);
- lostdcc(idx);
- }
- idx = dcc_total + 1;
- }
- if (idx == dcc_total) {
- putlog(LOG_MISC, "*",
- "(@) EOF socket %d, not a dcc socket, not anything.", i);
- close(i);
- killsock(i);
- }
- } else if (xx == -2 && errno != EINTR) { /* select() error */
- putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
- for (i = 0; i < dcc_total; i++) {
- if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno == EBADF)) {
- putlog(LOG_MISC, "*",
- "DCC socket %d (type %d, name '%s') expired -- pfft",
- dcc[i].sock, dcc[i].type, dcc[i].nick);
- killsock(dcc[i].sock);
- lostdcc(i);
- i--;
- }
- }
- } else if (xx == -3) {
- call_hook(HOOK_IDLE);
- socket_cleanup = 0; /* If we've been idle, cleanup & flush */
- }
-
- if (do_restart) {
- if (do_restart == -2)
- rehash();
- else {
- /* Unload as many modules as possible */
- int f = 1;
- module_entry *p;
- Function startfunc;
- char name[256];
-
- /* oops, I guess we should call this event before tcl is restarted */
- check_tcl_event("prerestart");
-
- while (f) {
- f = 0;
- for (p = module_list; p != NULL; p = p->next) {
- dependancy *d = dependancy_list;
- int ok = 1;
-
- while (ok && d) {
- if (d->needed == p)
- ok = 0;
- d = d->next;
- }
- if (ok) {
- strcpy(name, p->name);
- if (module_unload(name, botnetnick) == NULL) {
- f = 1;
- break;
- }
- }
- }
- }
-
- /* Make sure we don't have any modules left hanging around other than
- * "eggdrop" and the two that are supposed to be.
- */
- for (f = 0, p = module_list; p; p = p->next) {
- if (strcmp(p->name, "eggdrop") && strcmp(p->name, "encryption") &&
- strcmp(p->name, "uptime")) {
- f++;
- }
- }
- if (f != 0) {
- putlog(LOG_MISC, "*", MOD_STAGNANT);
- }
-
- flushlogs();
- kill_tcl();
- init_tcl(argc, argv);
- init_language(0);
-
- /* this resets our modules which we didn't unload (encryption and uptime) */
- for (p = module_list; p; p = p->next) {
- if (p->funcs) {
- startfunc = p->funcs[MODCALL_START];
- startfunc(NULL);
- }
- }
-
- rehash();
- restart_chons();
- call_hook(HOOK_LOADED);
- }
-
- do_restart = 0;
- }
+ eventloop();
}
}
diff -urN eggdrop1.6.19/src/patch.h eggdrop1.6.19+vwait/src/patch.h
--- eggdrop1.6.19/src/patch.h 2008-04-19 06:21:20.000000000 +0200
+++ eggdrop1.6.19+vwait/src/patch.h 2009-03-05 19:42:43.000000000 +0100
@@ -36,7 +36,7 @@
*
*
*/
-/* PATCH GOES HERE */
+patch("vwait");
/*
*
*
diff -urN eggdrop1.6.19/src/proto.h eggdrop1.6.19+vwait/src/proto.h
--- eggdrop1.6.19/src/proto.h 2008-02-16 22:41:04.000000000 +0100
+++ eggdrop1.6.19+vwait/src/proto.h 2009-03-05 19:41:16.000000000 +0100
@@ -181,6 +181,7 @@
void eggContextNote(const char *, int, const char *, const char *);
void eggAssert(const char *, int, const char *);
void backup_userfile(void);
+void eventloop(void);
/* match.c */
int _wild_match(register unsigned char *, register unsigned char *);
diff -urN eggdrop1.6.19/src/tclmisc.c eggdrop1.6.19+vwait/src/tclmisc.c
--- eggdrop1.6.19/src/tclmisc.c 2008-02-16 22:41:04.000000000 +0100
+++ eggdrop1.6.19+vwait/src/tclmisc.c 2009-03-05 19:41:23.000000000 +0100
@@ -55,6 +55,7 @@
extern int max_logs;
extern log_t *logs;
extern Tcl_Interp *interp;
+void mainbody();
int expmem_tclmisc()
{
@@ -705,6 +706,49 @@
return TCL_OK;
}
+static char *tcl_vwait_var STDVAR
+{
+ int *donePtr = (int *) cd;
+ *donePtr = 1;
+ return NULL;
+}
+
+static int tcl_vwait STDVAR
+{
+ int done;
+
+ BADARGS(2, 2, " name");
+
+ if (Tcl_TraceVar(interp, argv[1],
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ tcl_vwait_var, (ClientData) &done) != TCL_OK) {
+ return TCL_ERROR;
+ };
+ done = 0;
+ while (!done) {
+ eventloop();
+ if (Tcl_LimitExceeded(interp)) {
+ break;
+ }
+ }
+ Tcl_UntraceVar(interp, argv[1],
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ tcl_vwait_var, (ClientData) &done);
+
+ /*
+ * Clear out the interpreter's result, since it may have been set by event
+ * handlers.
+ */
+
+ Tcl_ResetResult(interp);
+ if (!done) {
+ Tcl_AppendResult(interp, "limit exceeded", NULL);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+
tcl_cmds tclmisc_objcmds[] = {
#ifdef USE_TCL_OBJ
{"md5", tcl_md5},
@@ -750,5 +794,6 @@
{"binds", tcl_binds},
{"callevent", tcl_callevent},
{"stripcodes", tcl_stripcodes},
+ {"eggvwait", tcl_vwait},
{NULL, NULL}
};
Sadly async fileevents on rather idle eggdrops will only get called once each second. So http async calls can be a lot slower than their sync counterparts.De Kus wrote:well you can almost everytime get the async behavior by using fileevent.
http has fileevents with callbacks already included, sockets work find with them server anyway. and where is the problem to bind for whois numeric for join binds? they are all much less trouble then somehow getting vwait to work. You kind of get vwait at any end of an script, because eggdrop loops until an event occours which basicly is what vwaits does afaik... it cyles in idle mode until an event occurs.
You're right. I changed my patch to create a new command called "eggvwait" instead of overwriting tcls vwait, so it can at least be safely patched without breaking the http module and other things which rely on the fast eventchecking. To *really* solve that issue we'd need to overwrite Tcls notifier (ugh).scotteh wrote: Sadly async fileevents on rather idle eggdrops will only get called once each second. So http async calls can be a lot slower than their sync counterparts.
well a dirty way to fix that is to doscotteh wrote: Sadly async fileevents on rather idle eggdrops will only get called once each second. So http async calls can be a lot slower than their sync counterparts.
Code: Select all
utimer 0 vwaitfix;proc vwaitfix {} {update;utimer 0 vwaitfix}
Code: Select all
diff -pNurX excludes eggdrop1.6.original/src/main.c eggdrop1.6.modified.tcleventloop/src/main.c
--- eggdrop1.6.original/src/main.c 2009-10-12 16:10:32.000000000 +0200
+++ eggdrop1.6.modified.tcleventloop/src/main.c 2009-11-20 02:00:00.000000000 +0100
@@ -941,7 +941,7 @@ int main(int argc, char **argv)
#ifdef USE_TCL_EVENTS
/* Process a single tcl event */
- Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
+ while (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT)) ;
#endif /* USE_TCL_EVENTS */
/* Lets move some of this here, reducing the numer of actual