bool SampleService::getFileInfos( BtpAction* action, DynamicObject& in, DynamicObject& out, DynamicObject& fileInfos) { bool rval; // do not send dyno as response out.setNull(); // get catalog interface CatalogInterface* ci = dynamic_cast<CatalogInterface*>( mNode->getModuleApiByType("bitmunk.catalog")); // get targeted node user DynamicObject vars; action->getResourceQuery(vars); if(!vars->hasMember("nodeuser")) { BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId()); } // get resource parameters DynamicObject params; action->getResourceParams(params); // populate ware bundle Ware ware; BM_ID_SET(ware["mediaId"], BM_MEDIA_ID(params[0])); MediaPreferenceList mpl; mpl[0]["preferences"][0]["contentType"] = vars["contentType"]; mpl[0]["preferences"][0]["minBitrate"] = 1; // FIXME: Make sure the node user is checked against logged in user? if((rval = ci->populateWareBundle( BM_USER_ID(vars["nodeuser"]), ware, mpl))) { FileInfoIterator i = ware["fileInfos"].getIterator(); while(i->hasNext()) { FileInfo& fi = i->next(); // FIXME: get content type for file info instead of "extension" const char* extension = fi["extension"]->getString(); // FIXME: only support for mp3 audio at this time if(strcmp(extension, "mp3") == 0) { // get sample range for file info Media media; BM_ID_SET(media["id"], BM_MEDIA_ID(fi["mediaId"])); if(getSampleRange(media)) { fi["media"] = media; fileInfos->append() = fi; } } } } return rval; }
/** * Recursively applies context to the given input object. * * @param ctx the context to use. * @param usedCtx the used context values. * @param predicate the related predicate or NULL if none. * @param in the input object. * @param out the contextualized output object. */ static void _applyContext( DynamicObject& ctx, DynamicObject& usedCtx, const char* predicate, DynamicObject& in, DynamicObject& out) { if(in.isNull()) { out.setNull(); } else { // initialize output DynamicObjectType inType = in->getType(); out->setType(inType); if(inType == Map) { // add context to each property in the map char* tmp = NULL; DynamicObjectIterator i = in.getIterator(); while(i->hasNext()) { // compact predicate DynamicObject& next = i->next(); DynamicObject cp(NULL); const char* p; if(strcmp(i->getName(), "@") == 0) { p = "@"; } else { cp = _compactString(ctx, usedCtx, NULL, i->getName(), &tmp); p = cp; } // recurse _applyContext(ctx, usedCtx, p, next, out[p]); } free(tmp); } else if(inType == Array) { // apply context to each object in the array DynamicObjectIterator i = in.getIterator(); while(i->hasNext()) { DynamicObject& next = i->next(); _applyContext(ctx, usedCtx, predicate, next, out->append()); } } // only strings need context applied, numbers & booleans don't else if(inType == String) { // compact string char* tmp = NULL; out = _compactString(ctx, usedCtx, predicate, in->getString(), &tmp); free(tmp); } } }
// Currently just handles top level and @:[...] constructs. static bool _findId(DynamicObject& in, const char* id, DynamicObject& out) { out.setNull(); if(in->hasMember("@")) { DynamicObject& _id = in["@"]; switch(_id->getType()) { // top level object case String: { if(_id == id) { out = in; } break; } // top level is blank node case Array: { bool found = false; DynamicObjectIterator i = _id.getIterator(); while(!found && i->hasNext()) { DynamicObject& next = i->next(); if(next["@"] == id) { out = next; found = true; } } break; } default: break; } } return true; }
/** * Recursively removes context from the given input object. * * @param ctx the context to use (changes during recursion as necessary). * @param in the input object. * @param out the normalized output object. * @param bnodeId the last blank node ID used. * * @return true on success, false on failure with exception set. */ static bool _removeContext( DynamicObject& ctx, DynamicObject& in, DynamicObject& out, int& bnodeId) { bool rval = true; if(in.isNull()) { out.setNull(); } else { // initialize output DynamicObjectType inType = in->getType(); out->setType(inType); // update context if(inType == Map && in->hasMember("#")) { ctx = in["#"]; } if(inType == Map) { rval = _normalize(ctx, in, NULL, &out, bnodeId); } else if(inType == Array) { // strip context from each object in the array DynamicObjectIterator i = in.getIterator(); while(i->hasNext()) { DynamicObject& next = i->next(); rval = _removeContext(ctx, next, out->append(), bnodeId); } } } return rval; }
bool SampleService::getSampleFileByIds( BtpAction* action, DynamicObject& in, DynamicObject& out, MediaId mediaId, FileId fileId) { bool rval; // do not send dyno as response out.setNull(); // determine if too busy or not bool permit = false; mSampleSemaphoreLock.lock(); { int current = mSampleSemaphore["current"]->getInt32(); if(current < mSampleSemaphore["max"]->getInt32()) { mSampleSemaphore["current"] = current + 1; permit = true; } } mSampleSemaphoreLock.unlock(); // ensure permit was granted to stream sample if(!permit) { // too many samples streaming action->getResponse()->getHeader()->setStatus(503, "Service Unavailable"); action->sendResult(); rval = true; } else { // get catalog interface CatalogInterface* ci = dynamic_cast<CatalogInterface*>( mNode->getModuleApiByType("bitmunk.catalog")); // get targeted node user DynamicObject vars; action->getResourceQuery(vars); if(!vars->hasMember("nodeuser")) { BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId()); } // get resource parameters DynamicObject params; action->getResourceParams(params); FileInfo fi; BM_ID_SET(fi["mediaId"], mediaId); BM_ID_SET(fi["id"], fileId); if((rval = ci->populateFileInfo(BM_USER_ID(vars["nodeuser"]), fi))) { // send the sample rval = sendFile(action, fi); } // release permit mSampleSemaphoreLock.lock(); { int current = mSampleSemaphore["current"]->getInt32(); mSampleSemaphore["current"] = current - 1; } mSampleSemaphoreLock.unlock(); if(!rval) { // sample not found action->getResponse()->getHeader()->setStatus(404, "Not Found"); action->sendResult(); rval = true; } } return rval; }