Roxen.git / server / modules / graphics / graphic_text.pike

version» Context lines:

Roxen.git/server/modules/graphics/graphic_text.pike:1: - constant cvs_version="$Id: graphic_text.pike,v 1.167 1999/05/08 00:52:43 per Exp $"; + constant cvs_version="$Id: graphic_text.pike,v 1.168 1999/05/12 08:00:35 per Exp $";   constant thread_safe=1;      #include <config.h>   #include <module.h>   #include <stat.h>   inherit "module";   inherit "roxenlib";      #ifndef VAR_MORE   #define VAR_MORE 0   #endif /* VAR_MORE */    -  +  + roxen.Configuration.ArgCache argcache; +  +    static private int loaded; - int args_restored = 0; +       static private string doc()   {    return !loaded?"":replace(Stdio.read_bytes("modules/tags/doc/graphic_text")    ||"", ({ "{", "}" }), ({ "&lt;", "&gt;" }));   }      array register_module()   {    return ({ MODULE_LOCATION | MODULE_PARSER,
Roxen.git/server/modules/graphics/graphic_text.pike:38:    catch(fnts = get_dir("fonts/32/") - ({".",".."}));    if(!fnts)    {    return ({});    }    return fnts;   }      void create()   { +  defvar("allowgenericurls", 1, +  "Allow generation of images with text from the URL", +  TYPE_FLAG, +  "If set, it will be possible to generate gtext images with the " +  "actual text in the URL. Use &lt;gtext-id&gt; to get the URL-prefix " +  "to use to generate images, then prepend the actual text"); +     defvar("cache_dir", "../gtext_cache", "Cache directory for gtext images",    TYPE_DIR,    "The gtext tag saves images when they are calculated in this "    "directory.");       defvar("cache_age", 48, "Cache max age",       TYPE_INT,       "If the images in the cache have not been accessed for this "
Roxen.git/server/modules/graphics/graphic_text.pike:91:    defvar("cols", 16, "Default number of colors per image", TYPE_INT_LIST,    "The default number of colors to use. 16 seems to be enough. "    "The size of the image depends on the number of colors",    ({ 1,2,3,4,5,6,7,8,10,16,32,64,128,256 }));       defvar("gif", 0, "Append .gif to all images", TYPE_FLAG|VAR_MORE,    "Append .gif to all images made by gtext. Normally this will "    "only waste bandwidth");       - #ifdef TYPE_FONT -  // compatibility variables... -  defvar("default_size", 32, 0, TYPE_INT,0,0,1); -  defvar("default_font", "urw_itc_avant_garde-demi-r",0,TYPE_STRING,0,0,1); - #else -  defvar("default_size", 32, "Default font size", TYPE_INT_LIST, -  "The default size for the font. This is used for the 'base' size, " -  "and can be scaled up or down in the tags.", -  ({ 16, 32, 64 })); +  defvar("cacheindb", 0, +  "Store the arguments and text cache in a mysql database", +  TYPE_FLAG|VAR_MORE, +  "If set, store the argument cache (and text cache) in a mysql " +  "database. This is very useful for load balancing using multiple " +  "roxen servers, since the mysql database handles synchronization");    -  defvar("default_font", "urw_itc_avant_garde-demi-r", "Default font", -  TYPE_STRING_LIST, -  "The default font. The 'font dir' will be prepended to the path", -  list_fonts()); - #endif +  defvar( "dbpath", "mysql://localhost/gtextcache", +  "Database URL to use", +  TYPE_STRING|VAR_MORE, +  "The database to use to store the argument cache", +  0, +  lambda(){ return !query("cacheindb"); });   }      string query_location() { return query("location"); }      static private mapping cached_args = ([ ]);      #define MAX(a,b) ((a)<(b)?(b):(a))      #if !efun(make_matrix)   static private mapping (int:array(array(int))) matrixes = ([]);
Roxen.git/server/modules/graphics/graphic_text.pike:195:    (int)(0.5+x-(sin((float)j/steps*3.145*2)*radie)),    (int)(0.5+y-(cos((float)j/steps*3.145*2)*radie)));    return on;   }      constant white = ({ 255,255,255 });   constant lgrey = ({ 200,200,200 });   constant grey = ({ 128,128,128 });   constant black = ({ 0,0,0 });    - object bevel(object in, int width, int|void invert) + object bevel(object in, int width, int|void invert)   {    int h=in->ysize();    int w=in->xsize();       object corner = Image.image(width+1,width+1);    object corner2 = Image.image(width+1,width+1);    object pix = Image.image(1,1);       for(int i=-1; i<=width; i++) {    corner->line(i,width-i,i,-1, @white);
Roxen.git/server/modules/graphics/graphic_text.pike:658:    if((time() - md) > (query("cache_age")*3600))    rm(query("cache_dir")+to_clean[0]);       to_clean = to_clean[1..];    if(sizeof(to_clean))    call_out(clean_cache_dir, 0.1);    else    call_out(clean_cache_dir, 3600);   }    + string error_status;   void start(int|void val, object|void conf)   {    loaded = 1;       if(conf)    { -  +  int id; +  string cp = query( "cache_dir" ), na = "args";    mkdirhier( query( "cache_dir" )+"/.foo" ); - #if constant(chmod) -  // FIXME: Should this error be propagated? -  catch { chmod( query( "cache_dir" ), 0777 ); }; - #endif +  if( query("cacheindb") ) +  { +  id = 1; +  cp = query("dbpath"); +  na = "gtext_arguments"; +  } +  mixed e; +  e = catch { +  argcache = conf->ArgCache( na, cp, id ); +  }; +  if( e ) +  { +  error_status = "Failed to initialize the GTEXT argument cache:\n" +  + (describe_backtrace( e )/"\n")[0]+"\n"; +  report_error( error_status ); +  werror( describe_backtrace( e ) ); +  error_status = "<font color=red size=+2>"+ +  html_encode_string(error_status)+"</font>"; +  } else +  error_status = 0;    remove_call_out(clean_cache_dir);    call_out(clean_cache_dir, 10);    mc = conf; -  base_key = "gtext:"+(conf?conf->name:roxen->current_configuration->name); +  base_key = "gtext:";    }   }    -  + mixed status() + { +  return error_status; + } +    #ifdef QUANT_DEBUG   void print_colors(array from)   {    for(int i=0; i<sizeof(from); i++)    perror("%d: %s\n", i, color_name(from[i]));   }   #endif      int number=0;      #ifdef THREADS   object number_lock = Thread.Mutex();   #define NUMBER_LOCK() do { object __key = number_lock->lock()   #define NUMBER_UNLOCK() if (__key) destruct(__key); } while(0)   #else /* !THREADS */   #define NUMBER_LOCK()   #define NUMBER_UNLOCK()   #endif /* THREADS */    - mapping find_cached_args(int num); -  +    constant nbsp = iso88591["&nbsp;"];      constant replace_from = indices( iso88591 )+ ({"&ss;","&lt;","&gt;","&amp",});   constant replace_to = values( iso88591 ) + ({ nbsp, "<", ">", "&", });      #define simplify_text( from ) replace(from,replace_from,replace_to)      #define CACHE_SIZE 2048      string FNAME(string a,string b)
Roxen.git/server/modules/graphics/graphic_text.pike:738: Inside #if constant(chmod)
  #if constant(chmod)    // FIXME: Should this error be propagated?    catch { chmod( FNAME(a,b), 0666 ); };   #endif    if(!fd) return;    fd->write(encode_value(({a,b,data})));    destruct(fd);   }       - array(int)|string write_text(int _args, string text, int size, object id) + array(int)|string write_text(string _args, string text, int size, object id)   {    string key = base_key+(cvs_version/" ")[2]+_args;    array err;    string orig_text = text;    mixed data; -  mapping args = find_cached_args(_args) || ([]); +  int elapsed; +  mapping args = argcache->lookup( _args ) || ([]);       if(data=cache_lookup(key, text))    {    if(args->nocache) // Remove from cache. Very useful for access counters    cache_remove(key, text);    if(size) return data[1];    return data[0];    } else if(data = get_cache_file( key, text )) {    cache_set(key, text, data);    if(size) return data[1];    return data[0];    } -  //werror("Not cached: %O -> %O\n", key, text); -  //werror("In cache: %O\n", sort(indices(cache->cache))); +        // So. We have to actually draw the thing... -  +  elapsed = gethrtime();    err = catch    {    object img;       if(!sizeof(args))    {    args=(["fg":"black","bg":"white","notrans":"1","nocache":"1"]);    text="Please reload this page";    }    if(!args->verbatim)
Roxen.git/server/modules/graphics/graphic_text.pike:899:    for(int i = 0; i<steps; i++)    {    int xp = i*ox/steps;    res += img->copy(xp, 0, xp+len, img->ysize(),    @parse_color(args->bg))->gif_add(0,0,delay);    }    res += img->gif_end();    data = ({ res, ({ len, img->ysize() }) });    }    +  elapsed = gethrtime()-elapsed; +  werror("elapsed: %d\n", elapsed);   // place in caches, as a gif image. -  if(!args->nocache) +  if(elapsed > 100*1000 && !args->nocache)    store_cache_file( key, orig_text, data );    cache_set(key, orig_text, data);    // werror("Cache set: %O -> %O\n", key, orig_text);    if(size) return data[1];    return data[0];    };   // werror("Got error < "+_args+" <"+text+">\n");    cache_set(key, text, 0);    throw(err);   }
Roxen.git/server/modules/graphics/graphic_text.pike:927:   {    if(f[-1]=='/') f = f[..strlen(f)-2];    if(sizeof(f/"/")==1) return ({ 509,-3,time(),time(),time(),0,0 });    int len=4711;    catch(len= strlen(find_file(f,rid)->data));    return ({ 33204,len,time(),time(),time(),0,0 });   }      array find_dir(string f, object rid)   { -  if(!strlen(f)) -  { -  if(!args_restored) restore_cached_args(); -  return Array.map(indices(cached_args), lambda(mixed m){return (string)m;}); +    } -  return ({"Example"}); - } +       mapping find_file(string f, object rid)   { -  int id; - #if constant(Gz) -  object g; - #endif +  string id;    -  if((rid->method != "GET") -  || (sscanf(f,"%d/%s", id, f) != 2)) +  if((rid->method != "GET") || (sscanf(f,"%[^/]/%s", id, f) != 2))    return 0;       if( query("gif") && f[strlen(f)-4..]==".gif") // Remove .gif    f = f[..strlen(f)-5];       if(!sizeof(f)) // No string to write.    return 0;    -  if (f[0] == '$') // Illegal in BASE64 +  if(f[0] != '^') +  { +  mapping t = argcache->lookup( f ); +  if(!t) +  error("Invalid text identifier. Aborting\n"); +  f = t->t; +  } else { +  if(QUERY(allowgenericurls))    f = f[1..]; - #if constant(Gz) -  else if (sizeof(indices(g=Gz))) -  catch(f = g->inflate()->inflate(MIME.decode_base64(f))); - #endif -  else -  catch(f = MIME.decode_base64(f)); -  +  }    // Generate the image.    return http_string_answer(write_text(id,f,0,rid), "image/gif");   } - mapping url_cache = ([]); +    string quote(string in)   { -  string option; -  if(option = url_cache[in]) return option; -  object g; -  if (sizeof(indices(g=Gz))) { -  option=MIME.encode_base64(g->deflate()->deflate(in)); -  } else { -  option=MIME.encode_base64(in); +  return argcache->store( ([ "t":in ]) );   } -  if(search(in,"/")!=-1) return url_cache[in]=option; -  string res="$"; // Illegal in BASE64 -  for(int i=0; i<strlen(in); i++) -  switch(in[i]) -  { -  case 'a'..'z': -  case 'A'..'Z': -  case '0'..'9': -  case '.': case ',': case '!': -  res += in[i..i]; -  break; -  default: -  res += sprintf("%%%02x", in[i]); -  } -  if(strlen(res) < strlen(option)) return url_cache[in]=res; -  return url_cache[in]=option; - } +     - #define ARGHASH query("cache_dir")+hash((cvs_version/" ")[2])+"ARGS_"+hash(mc->name) -  - int last_argstat; -  - void restore_cached_args() - { -  args_restored = 1; -  array a = file_stat(ARGHASH); -  if(a && (a[ST_MTIME] > last_argstat)) -  { -  last_argstat = a[ST_MTIME]; -  object o = open(ARGHASH, "r"); -  if(o) -  { -  string data = o->read(); -  catch { -  object q; -  if(sizeof(indices(q=Gz))) -  data=q->inflate()->inflate(data); -  }; -  catch { -  cached_args |= decode_value(data); -  }; -  } -  NUMBER_LOCK(); -  if (cached_args && sizeof(cached_args)) { -  number = sort(indices(cached_args))[-1]+1; -  } else { -  cached_args = ([]); -  number = 0; -  } -  NUMBER_UNLOCK(); -  } - } -  - void save_cached_args() - { -  restore_cached_args(); -  object o = open(ARGHASH, "wct"); -  if(o) -  { - #if constant(chmod) -  // FIXME: Should this error be propagated? -  catch { chmod( ARGHASH, 0666 ); }; - #endif -  string data=encode_value(cached_args); -  catch { -  object q; -  if(sizeof(indices(q=Gz))) -  data=q->deflate()->deflate(data); -  }; -  o->write(data); -  } - } -  - mapping find_cached_args(int num) - { -  if(!args_restored) restore_cached_args(); -  if(cached_args[num]) return cached_args[num]; -  restore_cached_args(); /* Not slow anymore, checks with stat... */ -  if(cached_args[num]) return cached_args[num]; -  return 0; - } -  - int find_or_insert(mapping find) - { -  mapping f2 = copy_value(find); -  int res; -  string q; -  -  foreach(glob("magic_*", indices(f2)), q) -  m_delete(f2,q); -  -  if(!args_restored) -  restore_cached_args( ); -  -  array a=indices(f2),b=values(f2); -  sort(a,b); -  q = a*""+((array(string))b)*""; -  -  if(res = cached_args[ q ]) -  return res; -  -  restore_cached_args(); /* Not slow now, checks with stat.. */ -  -  if(res = cached_args[ q ]) -  return res; -  -  int n; -  NUMBER_LOCK(); -  cached_args[ number ] = f2; -  cached_args[ q ] = number; -  n = number++; -  NUMBER_UNLOCK(); -  -  remove_call_out(save_cached_args); -  call_out(save_cached_args, 10); -  return n; - } -  -  +    string magic_javascript_header(object id)   {    if(!id->supports->netscape_javascript || !id->supports->images) return "";    return    ("\n<script>\n"    "function i(ri,hi,txt)\n"    "{\n"    " document.images[ri].src = hi.src;\n"    " setTimeout(\"top.window.status = '\"+txt+\"'\", 100);\n"    "}\n"
Roxen.git/server/modules/graphics/graphic_text.pike:1185:    arg->texture = fix_relative(arg->texture,id);    if(arg->magic_texture)    arg->magic_texture=fix_relative(arg->magic_texture,id);    if(arg->magic_background)    arg->magic_background=fix_relative(arg->magic_background,id);    if(arg->magicbg)    arg->magicbg = fix_relative(arg->magicbg,id);    if(arg->alpha)    arg->alpha = fix_relative(arg->alpha,id);    -  int num = find_or_insert( arg ); +  string id = argcache->store( arg );       if(!short) -  return query_location()+num+"/"; +  return query_location()+id+"/^";    else -  return (string)num; +  return id;   }      string tag_graphicstext(string t, mapping arg, string contents,    object id, object foo, mapping defines)   {    if((contents-" ")=="")    return "";       if(id->prestate->noimages)    {
Roxen.git/server/modules/graphics/graphic_text.pike:1305:    }       // Support for <gh1> like things.    if(sscanf(t, "%s%d", t, i)==2)    if(i > 1) arg->scale = 1.0 / ((float)i*0.6);       string na = arg->name, al=arg->align;    m_delete(arg, "name"); m_delete(arg, "align");       // Now the 'arg' mapping is modified enough.. -  int num = find_or_insert( arg ); +  string num = argcache->store( arg );       gt=contents;    rest="";       switch(t)    {    case "gh1": case "gh2": case "gh3": case "gh4":    case "gh5": case "gh6": case "gh7":    case "gh": pre="<p>"; post="<br>"; defalign="top"; break;    case "gtext":
Roxen.git/server/modules/graphics/graphic_text.pike:1397:    arg->fg = defines->alink||"#ff0000";    if(arg->magicbg) arg->background = arg->magicbg;    if(arg->bevel) arg->pressed=1;       foreach(glob("magic_*", indices(arg)), string q)    {    arg[q[6..]]=arg[q];    m_delete(arg, q);    }    -  int num2 = find_or_insert(arg); +  string num2 = argcache->store( arg );    array size = write_text(num2,gt,1,id);       if(!defines->magic_java) res = magic_javascript_header(id);    defines->magic_java="yes";       return replace(res +    magic_image(url||"", size[0], size[1], "i"+(defines->mi++),    query_location()+num+"/"+quote(gt)+gif,    query_location()+num2+"/"+quote(gt)+gif,    (arg->alt?arg->alt:replace(gt, "\"","'")),