1 /* Copyright (C) 2000-2005 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: client_base.pike,v 1.2 2008/07/17 16:45:00 astra Exp $
19 inherit "kernel/socket";
20 inherit "net/coal/binary";
25 class client_base : public socket,binary{
35 #define DEBUG_CLIENT(s, args...) werror(s+"\n", args)
37 #define DEBUG_CLIENT(s, args...)
40 private mapping mObjects; // objects
41 private string sLastPacket; // last package while communicating
42 private int iOID; // the object id of the current object
43 private int iTID; // the current transaction id
45 mapping mVariables; // session variables
50 function downloadStore;
53 private mixed miResult;
54 private int miCommand;
56 Thread.Mutex cmd_mutex = Thread.Mutex();
57 Thread.Condition cmd_cond = Thread.Condition();
58 Thread.Queue resultQueue = Thread.Queue();
59 Thread.Queue cmdQueue = Thread.Queue();
62 string connected_server;
70 private string identifier = 0;
72 private int(0..1) nowait;
73 private mapping(string:function) functions=([]);
79 int get_object_class() {
82 int id = set_object(oID);
83 mixed res = send_command(COAL_COMMAND, ({ "get_object_class" }));
92 object get_environment() {
93 return send_command(COAL_COMMAND, ({ "get_environment" }));
96 string get_identifier() {
97 if ( !stringp(identifier) ) {
99 int id = set_object(oID);
100 identifier = send_command(COAL_COMMAND, ({ "get_identifier" }));
107 void create(int id) {
112 return 1; // PSTAT_SAVE_OK
115 int no_wait(void|int(0..1) _nowait)
117 if(!zero_type(_nowait) && nowait == !_nowait)
126 string function_name(function fun)
128 return search(functions, fun);
135 catch{ describe=`->("describe")(); };
136 return sprintf("%s:%d/%s", connected_server, connected_port, describe);
139 function `->(string fun)
145 if(fun == "exec_code")
147 else if (fun=="serialize_coal")
150 functions[fun]=lambda(mixed|void ... args) {
151 return send_cmd(oID, fun, args, nowait);
153 return functions[fun];
157 function find_function(string fun)
160 functions[fun]=lambda(mixed|void ... args) {
161 return send_cmd(oID, fun, args, nowait);
163 return functions[fun];
175 int set_object(int|object|string id)
180 if ( objectp(mVariables[id]) )
181 iOID = mVariables[id]->get_object_id();
183 iOID = mVariables[id];
185 else if ( objectp(id) )
186 iOID = id->get_object_id();
200 object find_obj(int|string id)
204 object fp = send_cmd( 0, "get_module", "filepath:tree" );
205 object obj = send_cmd( fp, "path_to_object", id );
206 if ( !objectp(obj) ) return 0;
207 oid = obj->get_object_id();
211 if ( !mObjects[oid] ) {
212 mObjects[oid] = SteamObj(oid);
213 //werror("Created:"+master()->describe_object(mObjects[id])+"\n");
215 return mObjects[oid];
220 object find_object(int|string id) { return find_obj(id); }
222 mixed get_variable(string key)
224 return mVariables[key];
234 int connect_server(string server, int port)
248 if ( connect(server, port) ) {
249 MESSAGE("Connected to " + server + ":"+port +"\n");
250 connected_server=server;
252 __last_response = time(); // timestamp of last response
254 set_buffer(65536, "r");
255 set_buffer(65536, "w");
257 thread_create(read_thread);
258 thread_create(handle_commands);
269 int write(string str)
271 __last_response = time();
278 void handle_command(string func, mixed args) { }
282 void handle_commands()
285 while ( res = cmdQueue->read() ) {
287 if ( arrayp(res[1]) ) {
289 handle_command(res[1][0], res[1][1]);
292 werror("Fatal error while calling command: %O\n%O", err[0], err[1]);
299 void read_callback(object id, string data)
301 __last_response = time();
303 if ( functionp(downloadStore) ) {
307 __downloadBytes -= strlen(data);
308 if ( __downloadBytes <= 0 ) {
310 downloadStore = 0; // download finished
315 if ( __downloadBytes > 0 ) {
316 if ( __downloadBytes <= strlen(sLastPacket) )
317 resultQueue->write(sLastPacket);
321 res = receive_binary(sLastPacket);
322 while ( arrayp(res) ) {
326 if ( cmd == COAL_EVENT ) {
327 DEBUG_CLIENT("Event %O", res[1]);
329 DEBUG_CLIENT("RCVD Package(%d): Waiting for %d\n", tid, iWaitTID);
330 sLastPacket = res[2];
331 if ( tid == iWaitTID ) {
333 miCommand = res[0][1];
334 resultQueue->write(miResult);
336 else if ( cmd == COAL_COMMAND ) {
337 cmdQueue->write(res);
339 res = receive_binary(sLastPacket);
343 string download(int bytes, void|function store)
345 // actually the last command should have been the upload response,
346 // so there shouldnt be anything on the line except events
347 // which should have been already processed
348 // everything else should be download data
350 __downloadBytes = bytes;
352 if ( functionp(store) ) {
353 data = copy_value(sLastPacket[..bytes]);
354 __downloadBytes -= strlen(data);
355 if ( strlen(data) > 0 )
357 if ( __downloadBytes <= 0 ) {
361 downloadStore = store;
366 if ( strlen(sLastPacket) >= bytes ) {
367 data = copy_value(sLastPacket[..bytes]);
368 if ( bytes > strlen(sLastPacket) )
369 sLastPacket = sLastPacket[bytes+1..];
376 miResult = resultQueue->read();
377 data = copy_value(sLastPacket[..bytes]);
378 if ( strlen(sLastPacket) > bytes )
379 sLastPacket = sLastPacket[bytes+1..];
393 void handle_error(mixed err)
405 mixed send_command(int cmd, array args, int|void no_wait)
407 if ( !no_wait ) iWaitTID = iTID;
411 string msg = coal_compose(iTID++, cmd, iOID, 0, args);
412 string nmsg = copy_value(msg);
415 if ( no_wait ) return 0;
417 mixed result = resultQueue->read();
418 if ( miCommand == COAL_ERROR ) {
419 handle_error(result);
424 void subscribe_event(object obj, int eid, function callback)
426 int oid = set_object(obj);
427 send_command(COAL_SUBSCRIBE, ({ eid }) );
428 mEvents[eid] = callback;
432 mixed send_cmd(object|int obj, string func, mixed|void args, void|int no_wait)
434 int oid = set_object(obj);
435 if ( zero_type(args) )
437 else if ( !arrayp(args) )
439 mixed res = send_command(COAL_COMMAND, ({ func, args }), no_wait);
445 login(string name, string pw, int features, string|void cname, int|void novars)
447 if ( !stringp(cname) )
448 cname = "steam-pike";
452 loginData =send_command(COAL_LOGIN, ({ name, pw, cname, features, __id }));
455 send_command(COAL_LOGIN,({ name, pw, cname,CLIENT_FEATURES_ALL, __id}));
457 if ( arrayp(loginData) && sizeof(loginData) >= 9 ) {
458 mVariables["user"] = iOID;
459 foreach ( indices(loginData[8]), string key ) {
460 mVariables[key] = loginData[8][key];
462 mVariables["rootroom"] = loginData[6];
465 foreach ( values(loginData[9]), object cl ) {
466 set_object(cl->get_object_id());
467 mVariables[send_cmd(cl,"get_identifier")] = cl;
478 write(coal_compose(0, COAL_LOGOUT, 0, 0, 0));
484 resultQueue->write("");
489 void write_error2file(mixed|string err, int recursive) {
491 Stdio.File error_file;
497 directory = get_dir(path);
500 tmp_found=Stdio.exist(path+"/install_error."+file_counter);
502 file_counter = file_counter + 1;
510 file_counter = file_counter -1;
511 error_file=Stdio.File (path+"/install_error."+file_counter ,"cwa");
513 error_file->write(err);
516 foreach(err, mixed error){
517 if ( stringp(error) || intp(error) )
518 error_file->write((string)error);
519 else if ( objectp(error) )
520 error_file->write("<object...>\n");
521 else if ( arrayp(error) ){
522 write_error2file(error,1);
532 * Creates a new document object on the server.
534 * @param name the name of the new object
535 * @param where the container or room in which to create the new object
536 * @param mimetype (optional) the mime type of the new object (if not
537 * specified, the mime type will be determined by the object name)
538 * @param content (optional) the content for the new object (if not specified,
539 * the new object will not have any content)
540 * @return the newly created object (if an error occurs, an exception will be
543 object create_document ( string name, object where, void|string mimetype, void|string content )
545 if ( !stringp(name) || sizeof(name) < 1 )
546 throw( ({ "No name specified !" }) );
547 if ( !objectp(where) )
548 throw( ({ "No room or container specified !" }) );
549 object obj = send_cmd( where, "get_object_byname", name );
551 throw( ({ "Object \""+name+"\" already found !" }) );
552 object factory = send_cmd( 0, "get_factory", CLASS_DOCUMENT );
553 if ( !objectp(factory) )
554 throw( ({ "Document factory not found on server !" }) );
555 mapping params = ([ "name":name ]);
556 if ( stringp(mimetype) && sizeof(mimetype) > 0 )
557 params["mimetype"] = mimetype;
558 obj = send_cmd( factory, "execute", params );
560 throw( ({ "Could not create document !" }) );
561 send_cmd( obj, "move", where );
563 if ( stringp(content) )
564 send_cmd( obj, "set_content", content );
571 * Creates a new room object on the server.
573 * @param name the name of the new object
574 * @param where the room in which to create the new object
575 * @return the newly created object (if an error occurs, an exception will be
578 object create_room ( string name, object where )
580 if ( !stringp(name) || sizeof(name) < 1 )
581 throw( ({ "No name specified !" }) );
582 if ( !objectp(where) )
583 throw( ({ "No room specified !" }) );
584 object obj = send_cmd( where, "get_object_byname", name );
586 throw( ({ "Object \""+name+"\" already found !" }) );
587 object factory = send_cmd( 0, "get_factory", CLASS_ROOM );
588 if ( !objectp(factory) )
589 throw( ({ "Room factory not found on server !" }) );
590 obj = send_cmd( factory, "execute", ([ "name":name ]) );
592 throw( ({ "Could not create room !" }) );
593 send_cmd( obj, "move", where );
598 * Creates a new container object on the server.
600 * @param name the name of the new object
601 * @param where the container or room in which to create the new object
602 * @return the newly created object (if an error occurs, an exception will be
605 object create_container ( string name, object where )
607 if ( !stringp(name) || sizeof(name) < 1 )
608 throw( ({ "No name specified !" }) );
609 if ( !objectp(where) )
610 throw( ({ "No room or container specified !" }) );
611 object obj = send_cmd( where, "get_object_byname", name );
613 throw( ({ "Object \""+name+"\" already found !" }) );
614 object factory = send_cmd( 0, "get_factory", CLASS_CONTAINER );
615 if ( !objectp(factory) )
616 throw( ({ "Container factory not found on server !" }) );
617 obj = send_cmd( factory, "execute", ([ "name":name ]) );
619 throw( ({ "Could not create container !" }) );
620 send_cmd( obj, "move", where );