Changeset 47

Show
Ignore:
Timestamp:
07/26/07 01:54:10 (18 months ago)
Author:
scott
Message:

Beginning awkpaste phase #1

  • Adds a status record to the schema, with triggers making it a singleton.
  • Migrated from awkpp to cpp
  • Added status tracking to awkbot
  • Adds a socket library to the lib/ tree
  • A bootstrap is created so a temporary file can be allocated before awkbot actually starts.
    • This boot strap makes use of tempfile.awk, a new little function in it's own place
    • The bootstrap is called as a part of a larger, sh based bootstrapping which handles calls to cpp
  • Removes awkpp

NOTE: The code is kind of dirty as of this commit, particularly
trunk/awkbot/lib/awkbot.awk. It includes a lot of cruft which
can be removed or abstracted away. Further tickets should be created
to make sure this happens!

closes #52 & #53

Location:
trunk/awkbot
Files:
3 added
2 removed
7 modified

Legend:

Unmodified
Added
Removed
  • trunk/awkbot/awkbot.sql

    r8 r47  
    4646INSERT INTO `qna` VALUES ('mysql.awk','http://www.blisted.org/svn/modules/mysql.awk/ until tag writes documentation'); 
    4747 
     48 
     49CREATE TABLE `status` ( 
     50    `running` boolean not null default false, 
     51    `livefeed` varchar(120) default null 
     52); 
     53 
     54INSERT INTO `status` (running, livefeed) VALUES (FALSE, NULL); 
     55 
     56-- Make status a table with only one record, always 
     57-- Mysql is ghetto like that... we can't raise errors, we have to actually just 
     58-- create one with an invalid statement... 
     59 
     60DELIMITER /  
     61 
     62CREATE TRIGGER t_status_final BEFORE INSERT ON status 
     63FOR EACH ROW 
     64BEGIN 
     65    DECLARE temp integer; 
     66    SELECT `INSERT is not allowed` INTO temp FROM status; 
     67END; 
     68/ 
     69 
     70CREATE TRIGGER t_status_final_d BEFORE DELETE ON status 
     71FOR EACH ROW 
     72BEGIN 
     73    DECLARE temp integer; 
     74    SELECT `DELETE is not allowed` INTO temp FROM status; 
     75END; 
     76/ 
     77 
     78DELIMITER ; 
  • trunk/awkbot/etc/awkbot.conf

    r44 r47  
    22# IRC Stuff 
    33<irc> 
    4     nickname awkbot-test 
    5     altnick awkbot_test 
     4    nickname awktest 
     5    altnick awk_test 
    66    username awkbot 
    77    realname AWK IRC bot 
     
    2222 
    2323<mysql> 
    24     username tag 
    25     password darwin 
     24    username scott 
     25    password scott 
    2626    database awkbot 
    2727</mysql> 
  • trunk/awkbot/lib/awkbot.awk

    r44 r47  
    77# ----------------------------------------------------------------------------- 
    88 
    9 #include <assert.awk> 
    10 #include <config.awk> 
    11 #include <awkbot_db_mysql.awk> 
    12 #include <irc.awk> 
    13 #include <awkdoc.awk> 
    14 #include <join.awk> 
    15 #include <queue.awk> 
     9#import <assert.awk> 
     10#import <config.awk> 
     11#import <awkbot_db_mysql.awk> 
     12#import <irc.awk> 
     13#import <awkdoc.awk> 
     14#import <join.awk> 
     15#import <queue.awk> 
    1616 
    1717#define TEST 1 
     
    2929 
    3030BEGIN { 
    31 #    assert(irc,            "Awkbot depends on irc.awk") 
    32 #    assert(awkbot_config,  "Awkbot depends on config.awk") 
    33  
    3431    VERSION = "awkbot $Revision: 412 $" 
    3532 
     
    4138    assert(config("irc.server"), "server not specified in config") 
    4239 
     40    awkbot_db_init() 
     41 
    4342    irc_set("debug",    config("irc.debug")) 
    4443 
     
    5049    irc_register("privmsg") 
    5150    irc_register("ctcp") 
    52  
     51    irc_register("error") 
     52 
     53    print "Using", awkbot_db_status_livefeed(), "as live feed from awkbot" 
     54 
     55    # XXX Nasty hack, make this not need direct access to the irc array! 
     56    irc["tempfile"] = awkbot_db_status_livefeed() 
     57    irc_connect(config("irc.server")) 
     58} 
     59 
     60END { 
     61    awkbot_db_status_connected(0) 
     62} 
     63 
     64# Nasty hack to clean up every few records 
     65NR % 3 == 0 { 
     66    print "DEBUG: Truncating file.." 
     67    printf "" > irc["tempfile"]  
     68    fflush(irc["tempfile"]) 
     69    close(irc["tempfile"]) 
     70} 
     71$1 == "say" {  
     72    _msg = $3 
     73    for (i = 4; i < NF; i++) { 
     74        _msg = _msg " " $i 
     75    } 
     76    print "Saying " _msg " to " $2 
     77    irc_privmsg($2, _msg) 
     78} 
     79 
     80function irc_handler_error () { 
    5381    irc_connect(config("irc.server")) 
    5482} 
     
    6189 
    6290    if (msg) irc_sockwrite(msg "\r\n") 
     91 
     92    awkbot_db_status_connected(1) 
    6393} 
    6494 
     
    76106} 
    77107 
     108func calc (expr ,result,bc) { 
     109    bc = "bc -q" 
     110    print "scale=10" |& bc 
     111    print expr       |& bc 
     112    print "quit"     |& bc 
     113    bc |& getline result 
     114    close(bc) 
     115 
     116    # coerce to number 
     117    return result + 0 
     118} 
     119 
    78120function irc_handler_privmsg (nick, host, recipient, message, arg  \ 
    79121    ,direct,target,address,action,c_msg,argc,t,q,a) { 
     
    118160        # It's only numbers and stuff 
    119161        else if (c_msg ~ /^[0-9^.*+\/() -]*$/) { 
    120             action = "bc -q" 
    121             print "scale=10" |& action 
    122             print c_msg      |& action 
    123             print "quit"     |& action 
    124             action |& getline a 
    125             close(action) 
    126             irc_privmsg(target, address (a + 0))  
    127                 # Coerce the result into an array 
     162            irc_privmsg(target, address calc(c_msg))  
    128163        } 
    129164        else { 
     
    161196        } 
    162197    } 
     198    else if (arg[1] == nick) { 
     199        irc_privmsg(target, address "Talking about yourself, are we?") 
     200    } 
    163201} 
    164202 
  • trunk/awkbot/lib/awkbot_db_mysql.awk

    r44 r47  
    77# deps: assert.awk mysql.awk 
    88 
    9 #include <assert.awk> 
    10 #include <mysql.awk> 
     9#import <assert.awk> 
     10#import <config.awk> 
     11#import <mysql.awk> 
    1112 
    12 BEGIN { 
    13     # Config wont get parsed until awkbot's BEGIN {} block 
    14     irc_register("initialize") 
    15 } 
    16  
    17 function irc_handler_initialize () { 
     13function awkbot_db_init () { 
    1814    mysql_login(config("mysql.username"), config("mysql.password")) 
    1915    mysql_db(config("mysql.database")) 
     
    7874} 
    7975 
     76function awkbot_db_status_running (running) { 
     77    mysql_finish(mysql_query("UPDATE status SET running = " \ 
     78        running ? 1 : 0)) 
     79 
     80    if (! running)  
     81        mysql_finish(mysql_query("UPDATE status SET livefeed = null")) 
     82} 
     83 
     84function awkbot_db_status_connected (connected) { 
     85    mysql_finish(mysql_query("UPDATE status SET connected = " \ 
     86        connected ? 1 : 0)) 
     87} 
     88 
     89function awkbot_db_status_livefeed (filename    ,rv,row) { 
     90    if (filename) { 
     91        mysql_finish(mysql_query("UPDATE status SET livefeed = " \ 
     92                    mysql_quote(filename))) 
     93    } 
     94    else { 
     95        rv = mysql_query("SELECT livefeed FROM status") 
     96         
     97        mysql_fetch_row(rv, row) 
     98        filename = row[1] 
     99 
     100        mysql_finish(rv) 
     101    } 
     102 
     103    return filename 
     104} 
     105 
    80106function awkbot_db_info (keyword    ,result,rv,row) { 
    81107    rv = mysql_query("select keyword, text from info where keyword like " \ 
  • trunk/awkbot/lib/awkpaste.awk

    r44 r47  
    11#!/usr/bin/awk -f 
    22 
    3 #include <cgi-lib.awk> 
     3#import <cgi-lib.awk> 
    44 
    55BEGIN { 
  • trunk/awkbot/lib/cgi-lib.awk

    r44 r47  
    77# Set this globally so we don't have to ensure it happens anywhere else... 
    88    ORS = "\r\n" 
     9 
     10    # Handle uploads... 
     11 
     12    # gawk only 
     13    match(HEADER["Content-Disposition"], / filename="([^;]*)"/, r) 
     14    filename = r[1] ? r[1] : "multipart/mixed" 
     15 
     16    if (filename && multipart) { 
     17        tempfilename = tempfile("cgi-awk") 
     18    } 
     19 
     20    # When it's multipart, save headers and body together 
     21    if (multipart) { 
     22        for (key in HEADER) print key ":", HEADER[key] >> tempfilename 
     23        print "\r\n" >> tempfilename 
     24    } 
     25 
     26    while (buffersize < length(input)) { 
     27        getline i 
     28        print i >> tempfile 
     29    } 
     30 
     31    print cgi_read_buffer() >> tempfilename 
    932} 
    1033 
  • trunk/awkbot/lib/irc.awk

    r8 r47  
    1010# ----------------------------------------------------------------------------- 
    1111 
    12 # Init 
     12# This library implements the IRC protocol only.  An example of how to make it 
     13# work with gawk's /inet/tcp is provided below. 
    1314 
    14 BEGIN { 
    15     if (!irc["tempfile"]) irc["tempfile"] = irc_allocate_tempfile() 
    16  
    17     print "INIT" > irc["tempfile"] 
    18     close(irc["tempfile"]) 
    19  
    20     ARGV[ARGC++] = irc["tempfile"]  
    21 } 
    22  
    23 END { 
    24     system(sprintf("rm %s", irc["tempfile"])) 
    25 } 
    26  
     15#import <socket.awk> 
    2716 
    2817# ----------------------------------------------------------------------------- 
     
    8473# Connection API 
    8574function irc_privmsg (target, message) { 
    86     irc_sockwrite(sprintf("PRIVMSG %s :%s\r\n", target, message)) 
     75    irc_sockwrite(sprintf("PRIVMSG %s :%s", target, message)) 
    8776} 
    8877 
    8978function irc_ctcp (target, type, arg) { 
    90     irc_sockwrite(sprintf("PRIVMSG %s :\x01%s %s\x01\r\n", target, type, arg)) 
     79    irc_sockwrite(sprintf("PRIVMSG %s :\x01%s %s\x01", target, type, arg)) 
    9180} 
    9281 
    9382function irc_ctcp_reply (target, type, arg) { 
    94     irc_sockwrite(sprintf("NOTICE %s :\x01%s %s\x01\r\n", target, type, arg)) 
     83    irc_sockwrite(sprintf("NOTICE %s :\x01%s %s\x01", target, type, arg)) 
    9584} 
    9685 
    9786function irc_join (channel) { 
    98     irc_sockwrite(sprintf("JOIN %s\r\n", channel)) 
     87    irc_sockwrite(sprintf("JOIN %s", channel)) 
    9988} 
    10089 
    10190function irc_part (channel, message) { 
    102     irc_sockwrite(sprintf("PART %s :%s\r\n", channel, message)) 
     91    irc_sockwrite(sprintf("PART %s :%s", channel, message)) 
    10392} 
    10493 
    10594function irc_quit (message) { 
    106     irc_sockwrite(sprintf("QUIT :%s\r\n", message)) 
     95    irc_sockwrite(sprintf("QUIT :%s", message)) 
    10796} 
    10897 
    109 function irc_connect (host, port) {  
    110     irc_sockopen(host, port)  
    111     irc_sockwrite("NICK " irc["nickname"] "\n") 
    112     irc_sockwrite("USER " irc["username"] " a a :" irc["realname"] "\r\n") 
     98function irc_connect (server    ,t,host,port) {  
     99    # Pull host and port from host:port string 
     100    split(server, t, /:/) 
     101 
     102    host = t[1] 
     103    port = t[2] ? t[2] : 6667 
     104 
     105    socket_init(irc_socket, irc["tempfile"], !irc["tailpipe"]) 
     106    socket_connect(irc_socket, host, port) 
     107 
     108    irc_sockwrite("NICK " irc["nickname"]) 
     109    irc_sockwrite("USER " irc["username"] " a a :" irc["realname"]) 
    113110} 
    114111 
     
    118115# Raw internals 
    119116 
    120 function irc_allocate_tempfile (    mktemp,tempfile) { 
    121     if (! irc["command", "mktemp"]) mktemp = "mktemp /tmp/irc.awk.XXXXXX" 
    122     else mktemp = irc["command", "mktemp"] 
    123  
    124     mktemp | getline tempfile 
    125     close(mktemp) 
    126  
    127     return tempfile 
     117# Now just wraps socket_write 
     118function irc_sockwrite (data) { 
     119    socket_write(irc_socket, data "\r\n") 
    128120} 
    129121 
    130 function irc_sockwrite (data) { 
    131     if (irc["socket"]) printf data |& irc["socket"] 
    132     else irc_error("Attempt to write" data " to closed socket") 
     122# Just wraps socket_close 
     123function irc_sockclose () { 
     124    if (irc_socket) { 
     125        socket_close(irc_socket) 
     126    } 
    133127 
    134     if (irc["debug"]) printf "> %s\n", data 
    135 } 
    136  
    137 function irc_sockopen (host,port    ,t) { 
    138     if (! irc["socket"]) { 
    139         if (! port) { 
    140             if (host !~ /:/) { 
    141                 irc_error("irc_sockopen called without port number") 
    142             } 
    143  
    144             split(host,t,/:/) 
    145             host = t[1] 
    146             port = t[2] 
    147         } 
    148  
    149         irc["socket"] = "/inet/tcp/0/" host "/" port 
    150     } 
    151 } 
    152  
    153 function irc_sockclose () { 
    154     if (irc["socket"]) { 
    155         close(irc["socket"]) 
    156         delete irc["socket"] 
    157     } 
    158128    else irc_error("irc_sockclose called with no open socket") 
    159129} 
    160130 
    161131# ----------------------------------------------------------------------------- 
    162 # Main loop 
    163  
    164 {  
    165     if (irc["socket"]) { 
    166         # Get next line from socket and put in file for parsing 
    167         irc["socket"] |& getline 
    168      
    169         # Cycle Tempfile every 1000th line. 
    170         if (FNR == 1000) { 
    171             print > irc["tempfile"] 
    172             ARGV[ARGC++] = FILENAME 
    173             delete ARGV[ARGC - 2] 
    174         }  
    175          
    176         # Write to tempfile for next iteration 
    177         else print >> irc["tempfile"]  
    178         close(irc["tempfile"]) 
    179  
    180         if (irc["debug"]) print 
    181     } 
    182 } 
     132# This is an example main loop, awkbot used to use it.  I keep it in this 
     133# source file only as an example, and will some day soon move it out into a 
     134# test suite or some other bit of code.  This code is well tested, and works 
     135# like a charm, without flooding the filesystem with too much data. 
     136# 
     137# # Initialization 
     138# 
     139# BEGIN { 
     140#     if (!irc["tempfile"]) irc["tempfile"] = irc_allocate_tempfile() 
     141#  
     142#     print "INIT" > irc["tempfile"] 
     143#     close(irc["tempfile"]) 
     144#  
     145#     ARGV[ARGC++] = irc["tempfile"]  
     146# } 
     147#  
     148# # Cleanup 
     149# 
     150# END { 
     151#     system(sprintf("rm %s", irc["tempfile"])) 
     152# } 
     153#  
     154# # Main loop 
     155#  
     156# {  
     157# 
     158#     if (irc["using_inet_tcp"] && irc["socket"]) { 
     159#         # Get next line from socket and put in file for parsing 
     160#         irc["socket"] |& getline 
     161#      
     162#         # Cycle Tempfile every 1000th line. 
     163#         if (FNR == 1000) { 
     164#             print > irc["tempfile"] 
     165#             ARGV[ARGC++] = FILENAME 
     166#             delete ARGV[ARGC - 2] 
     167#         }  
     168#          
     169#         # Write to tempfile for next iteration 
     170#         else print >> irc["tempfile"]  
     171#         close(irc["tempfile"]) 
     172#  
     173#         if (irc["debug"]) print 
     174#     } 
     175# } 
    183176 
    184177END { if (irc["socket"]) close(irc["socket"]) }