db_connection.cc
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:14k
源码类别:

mpeg/mp3

开发平台:

C/C++

  1. /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
  2.    Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
  3.    Software license is located in file "COPYING"
  4. */
  5. #include <stdio.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <netdb.h>
  11. #include <errno.h>
  12. #include <iostream>
  13. #include <fstream>
  14. #include "session.h"
  15. #include "movie_item.h"
  16. #include "db_connection.h"
  17. #include "play_commands.h"
  18. #ifdef _gtk_main_win_h_
  19. #error "Don't mix database and user interface"
  20. #endif
  21. #ifdef _gtk_text_win_h_
  22. #error "Don't mix database and user interface"
  23. #endif
  24. void MovieItem::convertTime( const string &repr, struct tm &dest )
  25. {
  26.   // time in form: 1997-10-21 10:30:22.0
  27.   string s = repr;
  28.   *(char *)( s.data() + 4 ) = '';
  29.   *(char *)( s.data() + 7 ) = '';
  30.   *(char *)( s.data() + 10 ) = '';
  31.   *(char *)( s.data() + 13 ) = '';
  32.   *(char *)( s.data() + 16 ) = '';
  33.   *(char *)( s.data() + 19 ) = '';
  34.   dest.tm_year = strtol( s.data(), NULL, 10 ) - 1900;
  35.   dest.tm_mon = strtol( s.data() + 5, NULL, 10 ) - 1;
  36.   dest.tm_mday = strtol( s.data() + 8, NULL, 10 );
  37.   dest.tm_hour = strtol( s.data() + 11, NULL, 10 );
  38.   dest.tm_min = strtol( s.data() + 14, NULL, 10 );
  39.   dest.tm_sec = strtol( s.data() + 17, NULL, 10 );
  40. }
  41. // --------------------------------------------------
  42. db_iostream::db_iostream() : iostream(0), everything_read( true ) 
  43. {
  44.   skip_to_prompt();
  45. }
  46. istream& db_iostream::operator >>( string &s )
  47. {
  48.   if( everything_read ) {
  49.     s = "";
  50.     return *this;
  51.   }
  52.   char buf[1024];
  53.   if( before_mark ) 
  54.     {
  55.       // load until mark
  56.       while( !eof() )
  57. {
  58.   getline( buf, sizeof( buf ));
  59.   if( !buf[0] )
  60.     continue;
  61.   if( buf[0] == '#' ) {
  62.     messages.push_back( s );
  63.     continue;
  64.   }
  65.   if( !strcmp( buf, "->" )) {
  66.     before_mark = false;
  67.     break;
  68.   }
  69. }
  70.       if( everything_read ) {
  71. s = "";
  72. return *this;
  73.       }
  74.     }
  75.   while( !eof() )
  76.     {
  77.       getline( buf, sizeof( buf ));
  78.       // check for special messages, which may indicate error
  79.       if( !s.compare( "#!disconnect" ))
  80. throw DatabaseException( "disconnected" );
  81.       if( buf[0] == '#' ) {
  82. messages.push_back( s );
  83. continue;
  84.       }
  85.       if( !strcmp( buf, "<-" )) {
  86. skip_to_prompt();
  87. everything_read = true;
  88. break;
  89.       }
  90.       s = buf;
  91.       s.c_str();   // terminate
  92.       // cout << s << endl;
  93.       return *this;
  94.     }
  95.   s = "";
  96.   s.c_str();   // terminate
  97.   return *this;
  98. }
  99. void db_iostream::skip_to_prompt()
  100. {
  101.   char buf[ 1024 ];
  102.   // nothing to do
  103.   if( everything_read ) {
  104.     return;
  105.   }
  106.   while( !eof() )
  107.     {
  108.       int ch = peek();
  109.       if( ch == -1 )
  110. break;
  111.       if( ch != '>' )
  112. {
  113.   getline( buf, sizeof( buf ));
  114.   if( !buf[0] )
  115.     continue;
  116.   // check for special messages, which may indicate error
  117.   if( !strcmp( buf, "#!disconnect" ))
  118.     throw DatabaseException( "disconnected" );
  119.   if( ch == '#' ) {
  120.     string s( buf );
  121.     messages.push_back( s );
  122.   }
  123. }
  124.       else  // input char by char
  125. {
  126.   for( int i = 0; i < 3; i++ )
  127.     get( buf[i] );
  128.   buf[3] = '';
  129.   string s( buf );
  130.   if( !s.length() )
  131.     continue;
  132.   if( !s.compare( ">>>" )) 
  133.     {
  134.       // that means that we got the propmpt and the server will 
  135.       // really not post anything before the next command
  136.       everything_read = true;
  137.       break;
  138.     }
  139.   // ups! this is not our string... append the end of string
  140.   getline( buf + 3, sizeof( buf ) );
  141. }
  142.     }
  143. }
  144. void db_iostream::skip_to_prompt( vector< string > &msgs )
  145. {
  146.   skip_to_prompt();
  147.   append_messages( msgs );
  148. }
  149.   
  150. void db_iostream::append_messages( vector< string > &msgs )
  151. {
  152.   if( !messages.empty() )
  153.     msgs.insert( msgs.end(), messages.begin(), messages.end() );
  154.   messages.clear();
  155. }
  156. // --------------------------------------------------
  157. DbConnection::DbConnection() : dbSockStream( 0 )
  158. {
  159. }
  160. DbConnection::~DbConnection()
  161. {
  162.   if( dbSockStream )
  163.     delete dbSockStream;
  164.   dbSockStream = 0;
  165. }
  166. void DbConnection::connect( const string &server, unsigned int port )
  167. {
  168.   struct sockaddr_in name;
  169.   name.sin_family = AF_INET;
  170.   name.sin_port = htons (port);
  171.   struct hostent *hostinfo = gethostbyname ( server.c_str() );
  172.   if( hostinfo < 0 ) {
  173.     throw NetworkException( "bad host %s", server.c_str() );
  174.   }
  175.   name.sin_addr = *(struct in_addr *) hostinfo->h_addr;
  176.   // create socket
  177.   int dbSocket = socket (PF_INET, SOCK_STREAM, 0);
  178.   if( dbSocket < 0 )
  179.     {
  180.       dbSocket = 0;
  181.       throw NetworkException( "socket: %s", sys_errlist[ errno ] );
  182.     }
  183.   // now connect
  184.   if( 0 > ::connect( dbSocket, (struct sockaddr *) &name, sizeof (name)))
  185.     { 
  186.       dbSocket = 0;
  187.       throw NetworkException( "connect to %s: %s", server.c_str(),
  188.       sys_errlist[ errno ] );
  189.     }
  190.   filebuf *fb = new filebuf( dbSocket );
  191.   if( !fb )
  192.     {
  193.       dbSocket = 0;
  194.       throw NetworkException( "filebuf: %s", sys_errlist[ errno ] );
  195.     }
  196.   dbSockStream = new db_iostream( fb );
  197.   if( dbSockStream <= 0 )
  198.     {
  199.       dbSockStream = 0;
  200.       throw NetworkException( "socket stream: %s", sys_errlist[ errno ] );
  201.     }
  202. }
  203. bool DbConnection::login_superuser( const string &passwd, 
  204.     vector< string > &messages )
  205. {
  206.   *dbSockStream << _superuser_ << " " << passwd << endl;
  207.   dbSockStream->wait_input();
  208.   dbSockStream->skip_to_prompt( messages );
  209.   // if password is false, exception raise
  210.   return true;
  211. }
  212. const MovieItem &DbConnection::get_movie_by_id( int id )
  213. {
  214.   if( movies.find( id ) == movies.end() )
  215.     {
  216.       static MovieItem nothing;
  217.       return nothing;
  218.     }
  219.   return movies[ id ];
  220. }
  221. void DbConnection::skip_to_prompt( vector< string > &messages )
  222. {
  223.   dbSockStream->skip_to_prompt( messages );
  224. }
  225. // ==============================================================
  226. void DbConnection::set_debug( vector< string > &messages, int debugL )
  227. {
  228.   *dbSockStream << _debug_level_ << " " << debugL << endl;
  229.   dbSockStream->wait_input();
  230.   dbSockStream->skip_to_prompt( messages );
  231. }
  232. string DbConnection::get_database_name( vector< string > &messages )
  233. {
  234.   if( !dbSockStream )
  235.     throw NetworkException( "get database name: not connected" );
  236.   *dbSockStream << _database_name_ << endl;
  237.   dbSockStream->wait_input();
  238.   string res;
  239.   *dbSockStream >> res;
  240.   dbSockStream->skip_to_prompt( messages );
  241.   if( !res.length() )
  242.     throw SyntaxException( "get database name: empty" );
  243.   return res;
  244. }
  245. void DbConnection::load_new_database
  246. ( vector< string > &messages, const string &dbname )
  247. {
  248.   *dbSockStream << _database_name_ << " " << dbname << endl;
  249.   dbSockStream->wait_input();
  250.   dbSockStream->skip_to_prompt( messages );
  251.   // fill map again
  252.   movies.clear();
  253.   *dbSockStream << _list_movies_ << endl;
  254.   dbSockStream->wait_input();
  255.   
  256.   while( true )
  257.     {
  258.       string name;
  259.       *dbSockStream >> name;
  260.       if( !name.length() )
  261. break;
  262.       string idstr;
  263.       *dbSockStream >> idstr;
  264.       if( !idstr.length() )
  265. throw SyntaxException( "list movies: wrong reply" );
  266.       int id = atoi( idstr.c_str() );
  267.       string comments_lines_str;
  268.       *dbSockStream >> comments_lines_str;
  269.       if( !comments_lines_str.length() )
  270. throw SyntaxException( "list movies: wrong reply" );
  271.       int comments_lines = atoi( comments_lines_str.c_str() );
  272.       string comments;
  273.       for( ; comments_lines > 0; comments_lines -- )
  274. {
  275.   string tmps;
  276.   *dbSockStream >> tmps;
  277.   if( !tmps.length() )
  278.     throw SyntaxException( "list movies: wrong reply" );
  279.   comments += "n" + tmps;
  280. }
  281.       struct tm start;
  282.       string s;
  283.       *dbSockStream >> s;
  284.       if( !s.length() )
  285. throw SyntaxException( "list movies: wrong reply" );
  286.       MovieItem::convertTime( s, start );
  287.       struct tm stop;
  288.       *dbSockStream >> s;
  289.       if( !s.length() )
  290. throw SyntaxException( "list movies: wrong reply" );
  291.       MovieItem::convertTime( s, stop );
  292.       movies[ id ] = MovieItem( name, comments, start, stop );
  293.     }
  294.   dbSockStream->skip_to_prompt( messages );
  295.   dbSockStream->append_messages( messages );
  296.   char buf[200];
  297.   sprintf( buf, "%d movies in database", movies.size() );
  298.   messages.push_back( string( buf ) );
  299. }
  300. void DbConnection::load_movie_text( vector< string > &messages,
  301.     int id, TextOfMovieT *tom )
  302. {
  303.   *dbSockStream << _list_captions_ << " " << id << endl;
  304.   dbSockStream->wait_input();
  305.   tom->clear();
  306.   while( true ) 
  307.     {
  308.       string t;
  309.       *dbSockStream >> t;
  310.       if( !t.length() )
  311. break;
  312.       
  313.       struct tm start;
  314.       string s;
  315.       *dbSockStream >> s;
  316.       if( !s.length() )
  317. throw SyntaxException( "list captions: wrong reply" );
  318.       MovieItem::convertTime( s, start );
  319.       tom->push_back( StringOfText() );
  320.       StringOfText &sot = tom->back();
  321.       sot.set( t, start );
  322.     }
  323.   dbSockStream->skip_to_prompt( messages );
  324.   dbSockStream->append_messages( messages );
  325.   if( !tom->size() )
  326.     messages.push_back( "No text in movie" );
  327. }
  328. void DbConnection::getMovieFileListByTime( int id, const struct tm &t, 
  329.    MovieFilesT &movieFiles,
  330.    const Session &session,
  331.    vector< string > &messages )
  332. {
  333.   if( movies.find( id ) == movies.end() )
  334.     return;
  335.   // that means that this movie item may be just created by this line 
  336.   // and so its files count will be zero
  337.   MovieItem &mi = movies[ id ];
  338.   if( !mi.getMovieFilesCnt() )  // try to load them...
  339.     loadMovieFileList( id, mi, session, messages );
  340.   mi.findFileListByTime( t, movieFiles );
  341. }
  342. void DbConnection::loadMovieFileList( int id, MovieItem &mi,
  343.       const Session &session,
  344.       vector< string > &messages )
  345. {
  346.   *dbSockStream << _list_mov_files_ << " " << id << endl;
  347.   dbSockStream->wait_input();
  348.   mi.clearMovieFileList();
  349.   while( true ) 
  350.     {
  351.       string fname;
  352.       *dbSockStream >> fname;
  353.       if( !fname.length() )
  354. break;
  355.       string s_pushserv_id;
  356.       *dbSockStream >> s_pushserv_id;
  357.       if( !s_pushserv_id.length() )
  358. break;
  359.       int pushserv_id = atoi( s_pushserv_id.c_str() );
  360.       string ipaddr;
  361.       *dbSockStream >> ipaddr;
  362.       if( !ipaddr.length() )
  363. break;
  364.       string s_control_port;
  365.       *dbSockStream >> s_control_port;
  366.       if( !s_control_port.length() )
  367. break;
  368.       int control_port = atoi( s_control_port.c_str() );
  369.       struct tm start;
  370.       string s;
  371.       *dbSockStream >> s;
  372.       if( !s.length() )
  373. throw SyntaxException( "list captions: wrong reply" );
  374.       MovieItem::convertTime( s, start );
  375.       struct tm stop;
  376.       *dbSockStream >> s;
  377.       if( !s.length() )
  378. throw SyntaxException( "list captions: wrong reply" );
  379.       MovieItem::convertTime( s, stop );
  380.       mi.addMovieFile( fname, pushserv_id, ipaddr, control_port, start, stop );
  381.     }
  382.   dbSockStream->skip_to_prompt( messages );
  383.   // now select the best push server and filter the result
  384.   // ( we don't need to keep all servers who can play this movie )
  385.   vector< string > best_ips;
  386.   // we have it two now. I think that's enough
  387.   best_ips.push_back( session.best1PushServIP.str() );
  388.   best_ips.push_back( session.best2PushServIP.str() );
  389.   mi.filterBestPushServ( best_ips );
  390. }
  391. void DbConnection::loadServerProperties( vector< string > &messages,
  392.  ServerConfigItemVec &props )
  393. {
  394.   *dbSockStream << _list_properties_ << endl;
  395.   dbSockStream->wait_input();
  396.   
  397.   string numstr;
  398.   *dbSockStream >> numstr;
  399.   if( ! numstr.length() )
  400.     return;
  401.   int num = atoi( numstr.c_str() );
  402.   for( ; num > 0; num-- )
  403.     {
  404.       string k, v, h;
  405.       *dbSockStream >> k;
  406.       if( !k.length() )
  407. break;
  408.       *dbSockStream >> v;
  409.       if( !v.length() )
  410. break;
  411.       *dbSockStream >> h;
  412.       if( !h.length() )
  413. break;
  414.       ServerConfigItem ci( k, v, h );
  415.       props.push_back( ci );
  416.     }
  417.   dbSockStream->skip_to_prompt( messages );
  418. }
  419. void DbConnection::saveServerProperties( vector< string > &messages,
  420.  ServerConfigItemVec &props )
  421. {
  422.   for( int i = 0; i < props.size(); i++ )
  423.     {
  424.       ServerConfigItem &ci = props[i];
  425.       
  426.       *dbSockStream << _set_property_ << endl;
  427.       *dbSockStream << ci.key << "n" << ci.value << endl;
  428.       dbSockStream->wait_input();
  429.       dbSockStream->skip_to_prompt( messages );
  430.     }
  431.   *dbSockStream << _save_properties_ << endl;
  432.   dbSockStream->wait_input();
  433.   dbSockStream->skip_to_prompt( messages );
  434. }
  435. void DbConnection::fill_channellist( vector< string > &messages,
  436.      channel_infos_mapT &channel_infos_map )
  437. {
  438.   *dbSockStream << _list_channels_ << endl;
  439.   dbSockStream->wait_input();
  440.   // receive number of channels
  441.   string numstr;
  442.   *dbSockStream >> numstr;
  443.   if( !numstr.length() )
  444.     throw SyntaxException( "fill channellist: wrong reply" );
  445.   int num = atoi( numstr.c_str() );
  446.   for( int i = 0; i < num; i++ )
  447.     {
  448.       string idstr;
  449.       *dbSockStream >> idstr;
  450.       if( !idstr.length() )
  451. throw SyntaxException( "fill channellist: wrong reply" );
  452.       int Id = atoi( idstr.c_str() );
  453.       string portstr;
  454.       *dbSockStream >> portstr;
  455.       int port = atoi( portstr.c_str() );
  456.       string descr;
  457.       *dbSockStream >> descr;
  458.       
  459.       string activestr;
  460.       *dbSockStream >> activestr;
  461.       bool active = false;
  462.       if( !activestr.compare( "active" ) || !activestr.compare( "true" ))
  463. active = true;
  464.       // add this to the list
  465.       channel_info::add_new_channel_info( channel_infos_map, Id, port,
  466.   active, descr );
  467.     }
  468.   dbSockStream->skip_to_prompt( messages );
  469. }
  470. void DbConnection::start_recording( int channel_id, 
  471.     vector< string > &messages )
  472. {
  473.   char buf[10];
  474.   snprintf( buf, sizeof( buf ), "%d", channel_id );
  475.   *dbSockStream << _start_recording_ << "n" << buf << endl;
  476.   dbSockStream->wait_input();
  477.   dbSockStream->skip_to_prompt( messages );
  478. }
  479. void DbConnection::stop_recording( int channel_id,
  480.    vector< string > &messages )
  481. {
  482.   char buf[10];
  483.   snprintf( buf, sizeof( buf ), "%d", channel_id );
  484.   *dbSockStream << _stop_recording_ << "n" << buf << endl;
  485.   dbSockStream->wait_input();
  486.   dbSockStream->skip_to_prompt( messages );
  487. }
  488. // ====================== 
  489. NetworkException::NetworkException( const char *format, ... )
  490.   : BasicException()
  491. {
  492.   va_list ap;
  493.   va_start( ap, format );
  494.   init( format, ap );
  495.   va_end( ap );
  496. }
  497. SyntaxException::SyntaxException( const char *format, ... )
  498. {
  499.   va_list ap;
  500.   va_start( ap, format );
  501.   init( format, ap );
  502.   va_end( ap );
  503. }
  504. DatabaseException::DatabaseException( const char *format, ... )
  505. {
  506.   va_list ap;
  507.   va_start( ap, format );
  508.   init( format, ap );
  509.   va_end( ap );
  510. }