Commit e423f11f authored by Mark Tearle's avatar Mark Tearle
Browse files

Remove remaining bits of Bernard's postgres dispense

parent 9ac8ba25
API for the new dispense
-------------------------
New dispense is written in entirely in postgresql. The server does all the
required processing, meaning that database integrity is always maintained.
The current interface for dispense is using a postgresql client library.
Client libraries exist for many languages including C, C++, Perl, Python,
Ruby, PHP, or you could also speak with the supplied client 'psql' through
stdin/stdout.
The details for connecting to the database are:
hostname: dispense.ucc.gu.uwa.edu.au
username: anondispense
database: dispense
No password is required. You will only be able to connect from 'trusted'
machines - currently this is mussel, mermaid, morwong.
Note the API still isn't stable - it'd be worth running these commands by hand
to see what the resulting tables look like.
The useful things can be done once connected:
- SELECT * FROM get_services(username)
will give you a list of services available to the given user, including
syntax if parameters are required
- SELECT get_balance()
will return a table of all users and their balances.
- SELECT get_balance(username)
will return a table with one row for the given user, displaying their
account balance.
- SELECT do_request(target_user, service_name, parameters)
will perform a request.
* target_user is the user you wish to perform the request upon.
You will only be permitted to act on somebody else if you are in the
coke group.
* service_name is the name of the service as seen in the services
table.
* parameters is an array of parameters for the service, if required.
These should appear in the order as item_syntax from the services
table.
Example follows:
$ psql dispense -U anondispense -h dispense.ucc.gu.uwa.edu.au
\Welcome to psql 7.4.1, the PostgreSQL interactive terminal.
Type: \copyright for distribution terms
\h for help with SQL commands
\? for help on internal slash commands
\g or terminate with semicolon to execute query
\q to quit
-- Equivalent of bringing up the menu. Only items allowed for
-- the given user are shown.
dispense=> select * from get_services('dagobah');
item_name | item_cost_cents | item_syntax | item_stock
-------------+-----------------+--------------------------------------+------------
nothing | | |
give | | <username> <cents> |
acct | | <cents> <reason> |
passion pop | 80 | | 8
vb | 80 | | 0
emu export | 80 | | 3
champagne | 80 | | 9
coke powder | 80 | | 11
update_coke | | <slot number> <new name> <new price> |
opendoor | | |
grape juice | 80 | | 0
some foo | 77 | | 3
(12 rows)
-- Get balance for a user.
-- Equivalent of 'dispense acct dagobah'
-- Calling just get_balance() will return all users balances.
dispense=> select * from get_balance('dagobah');
user_name | user_balance_cents | user_balance_bytes
-----------+--------------------+--------------------
dagobah | -5080 | 0
(1 row)
-- Dispense something for a user.
-- Equivalent of 'dispense -u dagobah grape juice'
dispense=> select do_request('dagobah', 'grape juice', NULL);
ERROR: You may not dispense below -$20.00.
CONTEXT: PL/pgSQL function "do_request" line 12 at SQL statement
-- Adjust somebody's account balance up or down.
-- Equivalent of 'dispense acct dagobah +10000 BAG123'
dispense=> select do_request('dagobah', 'acct', array['+10000', 'BAG123']);
do_request
------------
t
(1 row)
-- Get the balance once again ... note that it's higher :)
dispense=> select * from get_balance('dagobah');
user_name | user_balance_cents | user_balance_bytes
-----------+--------------------+--------------------
dagobah | 4920 | 0
(1 row)
-- Try that dispense again, but we see there is none
dispense=> select do_request('dagobah', 'grape juice', NULL);
ERROR: We are out of stock of that item.
CONTEXT: PL/pgSQL function "do_request" line 12 at SQL statement
-- Try that dispense again, but we see there is none
dispense=> select do_request('dagobah', 'some foo', NULL);
do_request
------------
t
(1 row)
-- Updating a slot name/price on the coke machine
dispense=> select do_request('dagobah', 'update_coke', array['3', 'orange blah', '88']);
do_request
------------
t
(1 row)
-- Note the services have changed
dispense=> select * from get_services('dagobah');
item_name | item_cost_cents | item_syntax | item_stock
-------------+-----------------+--------------------------------------+------------
nothing | | |
give | | <username> <cents> |
acct | | <cents> <reason> |
passion pop | 80 | | 8
vb | 80 | | 0
emu export | 80 | | 3
champagne | 80 | | 9
coke powder | 80 | | 11
update_coke | | <slot number> <new name> <new price> |
opendoor | | |
grape juice | 80 | | 0
orange blah | 88 | | 3
(12 rows)
Email comments or queries to <[email protected]>
#!/usr/bin/python
import sys, os, re
from pyPgSQL import PgSQL
if __name__ == '__main__':
db = PgSQL.connect(user = 'anondispense', host = 'dispense', database = 'dispense')
cursor = db.cursor()
user = os.environ['USER']
if len(sys.argv) > 1:
# We have a request. Pass it to dispense by calling
# SELECT do_request(username, service, params as array)
service = sys.argv[1]
params = sys.argv[2:]
if params != []:
paramstr = 'array['
for i in params:
paramstr += '%s,'
paramstr = paramstr.rstrip(',') + ']'
else:
paramstr = 'NULL'
cursor.execute('SELECT do_request(%%s, %%s, %s)'%paramstr, [user, service]+params)
result = cursor.fetchone()[0]
if result == True:
print 'All good'
else:
print 'Eeeep!'
else:
cursor.execute('SELECT * FROM get_services(%s)', user)
print '%-10s %-50s %-10s %s' % ('Provider', 'Item', 'Cost', 'Stock')
print '-------------------------------------------------------------------------------'
for item in cursor.fetchall():
print '%10s '%item[0],
if item[3] is None:
item[3] = ''
print '%-50s'%(item[1]+' '+item[3]),
if item[2] is None:
print '%-10s' % '',
else:
print '%-10d' % int(item[2]),
if item[4] is None:
item[4] = 'N/A'
print '%s'%item[4]
cursor.execute('SELECT * FROM get_balance(%s)', user);
[_, cents,bytes] = cursor.fetchone()
print user, 'has', int(cents), 'cents and', int(bytes), 'bytes'
db.commit()
/* Prints a list of all usernames with useable coke balances
* delimited by newlines.
*
* - Bernard Blackham <[email protected]>
*/
#include <stdio.h>
#include "ucc.h"
int main(int argc, char* argv[]) {
char username[30];
int32 balance;
if (argc != 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
return 1;
}
SetCokebankToSocks();
cokebank_open();
printf("DELETE from users;\n");
printf("COPY users (user_name, user_balance_cents, user_balance_bytes) FROM stdin;\n");
while (cokebank_get_next(username, &balance, 0)) {
printf("%s\t%d\t%d\n", username, cokebank_get(username), cokebank_get_bytes(username));
}
printf("\\.\n");
cokebank_close();
return 0;
}
CC = gcc
INCLUDES = -I$(shell pg_config --includedir) -I$(shell pg_config --includedir-server)
CFLAGS = $(INCLUDES) -Wall -O2
all: pg_ident.so
pg_ident.so: pg_ident.o
gcc -shared -lident -o [email protected] $<
clean:
rm -f *.o *.so
#include <ident.h>
#include <postgres.h>
#include <miscadmin.h>
#include <libpq/libpq-be.h>
#include <fmgr.h>
char *ident_result = NULL;
PG_FUNCTION_INFO_V1(get_ident);
Datum get_ident(PG_FUNCTION_ARGS) {
IDENT *id;
if (MyProcPort == NULL)
elog(ERROR, "could not get ident for user: no port");
if (!ident_result) {
id = ident_lookup(MyProcPort->sock, 5);
if (id && id->identifier) ident_result = strdup(id->identifier);
}
if (ident_result) {
int len;
VarChar* result;
len = strlen(ident_result);
if (len > 8) len = 8;
result = palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), ident_result, len);
PG_RETURN_VARCHAR_P(result);
}
elog(ERROR, "could not get ident for user: ident failed");
/* not reached */
PG_RETURN_NULL();
}
This diff is collapsed.
DELETE FROM cokecontrollers;
DELETE FROM doorcontrollers;
COPY cokecontrollers (user_name, reason) FROM stdin;
root automatic
bers 19990421
mjdawson 19990421
mtearle 19990421
nick 19990421
japester 19990421
maset 19990421
djinn 19990519
grahame 19990714
maelstrm 19991208
trs80 20000822
tieryn 20010328
dayta 20010328
ack 20010510
colm 20010510
davidb 20010510
nikita 20010510
fitz 20010510
omailes 20010712
matt 20020412
susie 20020809
griffin 20020809
tpope 20021018
maelkann 20021031
dagobah 20030401
thebmw 20030401
coxy 20031010
\.
COPY doorcontrollers (user_name, reason) FROM stdin;
root by default
trs80 meeting 2000-05-18 cos he\'s cool
chas meeting 2000-05-18 he\'s always in
matt the not meeting of 2002-01-04
thebmw the meeting of 2002-08-09
susie the sgm of 2002-10-18
velithya blah
coxy meeting 2003-03-07
dagobah meeting 2003-03-07
davyd meeting 2003-03-07
grahame cos
falstaff some time
griffin foo
vegeta shrug
\.
CC = gcc
INCLUDES = -I$(shell pg_config --includedir) -I$(shell pg_config --includedir-server)
CFLAGS = $(INCLUDES) -Wall -O2
all: pg_syslog.so
pg_syslog.so: pg_syslog.o
gcc -shared -o [email protected] $<
clean:
rm -f *.o *.so
#include <syslog.h>
#include <postgres.h>
#include <miscadmin.h>
#include <libpq/libpq-be.h>
#include <fmgr.h>
PG_FUNCTION_INFO_V1(logmsg);
Datum logmsg(PG_FUNCTION_ARGS) {
text* arg0;
char* msg;
int len;
arg0 = PG_GETARG_TEXT_P(0);
len = arg0->vl_len - VARHDRSZ;
msg = (char*) palloc(len+1);
memcpy(msg, arg0->vl_dat, len);
msg[len] = '\0';
openlog("postgres", LOG_PID, LOG_LOCAL6);
syslog(LOG_INFO, "[%s]: %s", GetUserNameFromId(GetUserId()), msg);
closelog();
pfree(msg);
/* not reached */
PG_RETURN_VOID();
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment