void Agent::streamData (ostream & out, std::set<string> & aFilter, bool current, unsigned int aInterval, uint64_t start, unsigned int count, unsigned int aHeartbeat ) { // Create header string boundary = md5(intToString(time(NULL))); ofstream log; if ( mLogStreamData ) { string filename = "Stream_" + getCurrentTime(LOCAL) + "_" + int64ToString((uint64_t) dlib::get_thread_id( )) + ".log"; log.open(filename.c_str( )); } out << "HTTP/1.1 200 OK\r\n" "Date: " << getCurrentTime(HUM_READ) << "\r\n" "Server: MTConnectAgent\r\n" "Expires: -1\r\n" "Connection: close\r\n" "Cache-Control: private, max-age=0\r\n" "Content-Type: multipart/x-mixed-replace;boundary=" << boundary << "\r\n" "Transfer-Encoding: chunked\r\n\r\n"; // This object will automatically clean up all the observer from the // signalers in an exception proof manor. ChangeObserver observer; // Add observers std::set<string>::iterator iter; for ( iter = aFilter.begin( ); iter != aFilter.end( ); ++iter ) { mDataItemMap[*iter]->addObserver(&observer); } uint64_t interMicros = aInterval * 1000; uint64_t firstSeq = getFirstSequence( ); if ( start < firstSeq ) { start = firstSeq; } try { // Loop until the user closes the connection timestamper ts; while ( out.good( ) ) { // Remember when we started this grab... uint64_t last = ts.get_timestamp( ); // Fetch sample data now resets the observer while holding the sequence // mutex to make sure that a new event will be recorded in the observer // when it returns. string content; uint64_t end; bool endOfBuffer = false; if ( current ) { content = fetchCurrentData(aFilter, NO_START); } else { // Check if we're falling too far behind. If we are, generate an // MTConnectError and return. if ( start < getFirstSequence( ) ) { sLogger << LWARN << "Client fell too far behind, disconnecting"; throw ParameterError("OUT_OF_RANGE", "Client can't keep up with event stream, disconnecting"); } else { // end and endOfBuffer are set during the fetch sample data while the // mutex is held. This removed the race to check if we are at the end of // the bufffer and setting the next start to the last sequence number // sent. content = fetchSampleData(aFilter, start, count, end, endOfBuffer, &observer); } if ( mLogStreamData ) { log << content << endl; } } ostringstream str; // Make sure we're terminated with a <cr><nl> content.append("\r\n"); out.setf(ios::dec, ios::basefield); str << "--" + boundary << "\r\n" "Content-type: text/xml\r\n" "Content-length: " << content.length( ) << "\r\n\r\n" << content; string chunk = str.str( ); out.setf(ios::hex, ios::basefield); out << chunk.length( ) << "\r\n"; out << chunk << "\r\n"; out.flush( ); // Wait for up to frequency ms for something to arrive... Don't wait if // we are not at the end of the buffer. Just put the next set after aInterval // has elapsed. Check also if in the intervening time between the last fetch // and now. If so, we just spin through and wait the next interval. // Even if we are at the end of the buffer, or within range. If we are filtering, // we will need to make sure we are not spinning when there are no valid events // to be reported. we will waste cycles spinning on the end of the buffer when // we should be in a heartbeat wait as well. if ( current || !endOfBuffer ) { // If this is not a current, move the start to the end. This is only significant // if we are not at the end of the buffer and we are scanning through the event // buffer. if ( !current ) { start = end; } // Measure the delta time between the point you last fetched data to now. uint64 delta = ts.get_timestamp( ) - last; if ( delta < interMicros ) { // Sleep the remainder dlib::sleep(( interMicros - delta ) / 1000); } } else if ( observer.wait(aHeartbeat) ) { // Make sure the observer was signaled! if ( !observer.wasSignaled( ) ) { sLogger << LERROR << "Agent::streamData: Observer returned true from wait, but observer was not signaled. Closing connection..."; throw ParameterError("INTERNAL_ERROR", "Event observer failed"); } // Get the sequence # signaled in the observer when the earliest event arrived. // This will allow the next set of data to be pulled. Any later events will have // greater sequence numbers, so this should not cause a problem. Also, signaled // sequence numbers can only decrease, never increase. start = observer.getSequence( ); // Now wait the remainder if we triggered before the timer was up. uint64 delta = ts.get_timestamp( ) - last; if ( delta < interMicros ) { // Sleep the remainder dlib::sleep(( interMicros - delta ) / 1000); } } else { // If nothing came out during the last wait, we may have still have advanced // the sequence number. We should reset the start to something closer to the // current sequence. If we lock the sequence lock, we can check if the observer // was signaled between the time the wait timed out and the mutex was locked. // Otherwise, nothing has arrived and we set to the next sequence number to // the next sequence number to be allocated and continue. dlib::auto_mutex lock(*mSequenceLock); if ( observer.wasSignaled( ) ) { start = observer.getSequence( ); } else { start = mSequence; } } } } catch ( ParameterError & aError ) { sLogger << LINFO << "Caught a parameter error."; if ( out.good( ) ) { string content = printError(aError.mCode, aError.mMessage); out << "--" + boundary << "\n" "Content-type: text/xml\n" "Content-length: " << content.length( ) << "\n\n" << content; out.flush( ); } } catch ( ... ) { sLogger << LWARN << "Error occurred during streaming data"; if ( out.good( ) ) { string content = printError("INTERNAL_ERROR", "Unknown error occurred during streaming"); out << "--" + boundary << "\n" "Content-type: text/xml\n" "Content-length: " << content.length( ) << "\n\n" << content; out.flush( ); } } out.setstate(ios::badbit); // Observer is auto removed from signalers }
boolean RasterCode::GConstDecls(ostream& out) { out << "(Raster*, Graphic* gr = nil);\n"; out << " virtual Graphic* Copy();\n"; return out.good(); }
boolean RasterCode::Definition (ostream& out) { boolean ok = true; const char* sfile; IRasterComp* rastercomp = GetIRasterComp(); RasterComp* target = (RasterComp*) rastercomp->GetTarget(); RasterRect* raster = target->GetRasterRect(); SubclassNameVar* cnamer = rastercomp->GetCClassNameVar(); SubclassNameVar* gnamer = rastercomp->GetGClassNameVar(); MemberNameVar* mnamer = rastercomp->GetMemberNameVar(); const char* mname = mnamer->GetName(); const char* cname = cnamer->GetName(); const char* gname = gnamer->GetName(); if (_emitInstanceDecls || _emitGraphicState) { ok = ok && GraphicCodeView::Definition(out); } else if (_emitInstanceInits) { static int raster_id; char substName[CHARBUFSIZE]; sfile = target->GetFileName(); Catalog* catalog = unidraw->GetCatalog(); if (sfile == nil) { sprintf(substName, "raster%d.ps", raster_id++); sfile = substName; } if (!catalog->Exists(sfile)) { char orig[CHARBUFSIZE]; const char* name = catalog->GetName(rastercomp->GetRoot()); char* dir = GetDirName(name); char* index = strrchr(sfile, '/'); if (index == nil) { strcpy(orig, sfile); } else { strcpy(orig, &index[1]); } strcpy(substName, dir); strcat(substName, orig); sfile = substName; if (!catalog->Exists(sfile)) { catalog->Save(target, sfile); } } out << " {\n"; out << " RasterComp* " << mname << "_comp = (RasterComp*) "; out << "ImportCmd::Import(\"" << sfile << "\");\n"; out << " Raster* " << mname << "_raster = "; out << mname << "_comp->GetRasterRect()->GetOriginal();\n"; if (_emitGraphicComp) { out << " " << mname << "_gr"; } else { out << " " << mname; } out << " = new " << gname << "(" << mname << "_raster, "; out << mname << "_comp->GetGraphic());\n"; out << " delete " << mname << "_comp;\n"; ok = WriteGraphicInits(raster, out); if (_emitGraphicComp) { out << " " << mname << " = new " << cname << "("; out << mname << "_gr, \"" << sfile << "\");\n"; out << " " << mname << "->Update();\n"; } out << " }\n"; } else if (_emitExpHeader) { ok = ok && GraphicCodeView::Definition(out); if (strcmp(gname, _classname) == 0) { if (!_namelist->Search("raster")) { _namelist->Append("raster"); out << "#include <InterViews/raster.h> \n"; } } } else { ok = ok && GraphicCodeView::Definition(out); } return ok && out.good(); }
boolean TextEditCode::Definition (ostream& out) { boolean ok = true; if ( _emitProperty || _emitInstanceDecls || _emitClassHeaders || _emitHeaders || _emitForward ) { return CodeView::Definition(out); } else if (_emitExpHeader) { InteractorComp* icomp = GetIntComp(); MemberNameVar* mnamer = icomp->GetMemberNameVar(); SubclassNameVar* snamer = icomp->GetClassNameVar(); if (!snamer->IsSubclass()) { if ( _scope && mnamer->GetExport()&&!_namelist->Search("texteditor") ) { _namelist->Append("texteditor"); out << "#include <InterViews/texteditor.h>\n"; out << "#include <InterViews/textbuffer.h>\n"; } } else { ok = ok && CodeView::Definition(out); } } else if (_emitCorehHeader) { InteractorComp* icomp = GetIntComp(); SubclassNameVar* snamer = icomp->GetClassNameVar(); const char* subclass = snamer->GetName(); if (snamer->IsSubclass() && strcmp(subclass, _classname) == 0) { if (!_namelist->Search("texteditor")) { _namelist->Append("texteditor"); out << "#include <InterViews/texteditor.h>\n"; } } } else if (_emitInstanceInits) { InteractorComp* icomp = GetIntComp(); const char* mname = icomp->GetMemberNameVar()->GetName(); if (!_instancelist->Find((void*) mname)) { _instancelist->Append(new UList((void*)mname)); TextEditComp* tc = GetTextEditComp(); int rows, cols; BeginInstantiate(out); StrBrowserGraphic* graphic = tc->GetStrBrowserGraphic(); graphic->GetRowsCols(rows, cols); out << "("; InstanceName(out); out << rows << ", " << cols << ", " << 4 << ", Reversed" << ");\n"; out << " " << mname; out << "->Edit(new TextBuffer(new char[256], 0, 256))"; EndInstantiate(out); } } else if ( _emitFunctionDecls || _emitFunctionInits || _emitBSDecls || _emitBSInits ) { return true; } else if ( _emitCoreDecls || _emitCoreInits || _emitClassDecls || _emitClassInits ) { ok = ok && CodeView::Definition(out); } else if (_emitMain) { ok = ok && CodeView::Definition(out); } return out.good() && ok; }
boolean TextEditCode::ConstDecls(ostream& out) { out << "(const char*, int r, int c, int t, int h);\n"; return out.good(); }
int FixedLengthBuffer::write(ostream& stream) const{ int recAddr = stream.tellp(); stream.write(this->buffer, this->bufferSize); if(!stream.good()) return -1; return recAddr; }
boolean ScrollerCode::ConstDecls(ostream& out) { out << "(const char*, Interactor* i);\n"; return out.good(); }
boolean ScrollerCode::Definition (ostream& out) { boolean ok = true; if ( _emitProperty || _emitInstanceDecls || _emitForward || _emitClassHeaders || _emitHeaders ) { return CodeView::Definition(out); } else if (_emitExpHeader) { InteractorComp* icomp = GetIntComp(); MemberNameVar* mnamer = icomp->GetMemberNameVar(); SubclassNameVar* snamer = icomp->GetClassNameVar(); if (!snamer->IsSubclass()) { if ( _scope && mnamer->GetExport() && !_namelist->Search("scroller") ) { _namelist->Append("scroller"); out << "#include <InterViews/scroller.h>\n"; } } else { ok = ok && CodeView::Definition(out); } } else if (_emitCorehHeader) { InteractorComp* icomp = GetIntComp(); SubclassNameVar* snamer = icomp->GetClassNameVar(); const char* subclass = snamer->GetName(); if (snamer->IsSubclass() && strcmp(subclass, _classname) == 0) { if (!_namelist->Search("scroller")) { _namelist->Append("scroller"); out << "#include <InterViews/scroller.h>\n"; } } } else if (_emitInstanceInits) { InteractorComp* icomp = GetIntComp(); InteractorComp* ctarget = nil; const char* mname = icomp->GetMemberNameVar()->GetName(); MemberNameVar* mnamer = (MemberNameVar*) icomp->GetState( "AdjusteeVar" ); const char* scrollee = mnamer->GetName(); if (*scrollee == '\0') { if (_err_count < 10) { strcat(_errbuf, mname); strcat(_errbuf, " has undefined scrolling target.\n"); _err_count++; } return false; } else if (!Search(mnamer, ctarget)) { if (_err_count < 10) { strcat(_errbuf, mname); strcat( _errbuf, "'s scrolling target is not in the same hierarchy.\n" ); _err_count++; } return false; } else if (ctarget != nil && !icomp->IsRelatableTo(ctarget)) { if (_err_count < 10) { strcat(_errbuf, mname); strcat( _errbuf, "'s adjusting target is not subclassed nor adjustable.\n" ); _err_count++; } return false; } if (_instancelist->Find((void*) scrollee)) { if (!_instancelist->Find((void*) mname)) { _instancelist->Append(new UList((void*)mname)); scrollee = (*scrollee == '\0') ? "nil" : scrollee; BeginInstantiate(out); out << "("; InstanceName(out); out << scrollee << ")"; EndInstantiate(out); _icomplete = true; } } else { _icomplete = false; } } else if ( _emitBSDecls || _emitBSInits || _emitFunctionDecls || _emitFunctionInits ) { return true; } else if ( _emitCoreDecls || _emitCoreInits || _emitClassDecls || _emitClassInits ) { ok = ok && CodeView::Definition(out); } else if (_emitMain) { ok = ok && CodeView::Definition(out); } return out.good() && ok; }