Esempio n. 1
0
void loom_asset_pump()
{
   // Currently we only want to do this on the main thread so piggy back on the
   // native delegate sanity check to bail if on secondary thread.
   if(platform_getCurrentThreadId() != LS::NativeDelegate::smMainThreadID && LS::NativeDelegate::smMainThreadID != 0xBAADF00D)
      return;

   loom_mutex_lock(gAssetLock);

   // Talk to the asset server.
   loom_asset_serviceServer();

   // For now just blast all the data from each file into the asset.
   while(gAssetLoadQueue.size())
   {
      loom_asset_t *asset = gAssetLoadQueue.front();

      // Figure out the type from the path.
      utString path = asset->name;
      int type = loom_asset_recognizeAssetTypeFromPath(path);
      
      if(type == 0)
      {
         lmLog(gAssetLogGroup, "Could not infer type of resource '%s', skipping it...", path.c_str());
         asset->state = loom_asset_t::Unloaded;
         gAssetLoadQueue.erase((UTsize)0, true);
         continue;
      }

      // Open the file.
      void *ptr;
      long size;
      if(!platform_mapFile(asset->name.c_str(), &ptr, &size))
      {
         lmAssert(false, "Could not open file '%s'.", asset->name.c_str());
      }

      // Deserialize it.
      LoomAssetCleanupCallback dtor = NULL;
      void *assetBits = loom_asset_deserializeAsset(path, type, size, ptr, &dtor);

      // Close the file.
      platform_unmapFile(ptr);

      // Instate the asset.
      asset->instate(type, assetBits, dtor);

      // Done! Update queue.
      gAssetLoadQueue.erase((UTsize)0, true);
   }

   loom_mutex_unlock(gAssetLock);
}
Esempio n. 2
0
// Entry point for the socket thread. Listen for connections and incoming data,
// and route it to the protocol handlers.
static int socketListeningThread(void *payload)
{
    // Listen for incoming connections.
    int listenPort = 12340;

    gListenSocket = (loom_socketId_t)-1;
    for ( ; ; )
    {
        gListenSocket = loom_net_listenTCPSocket(listenPort);

        if (gListenSocket != (loom_socketId_t)-1)
        {
            break;
        }

        lmLogWarn(gAssetAgentLogGroup, "   - Failed to acquire port %d, trying port %d", listenPort, listenPort + 1);
        listenPort++;
    }

    lmLog(gAssetAgentLogGroup, "Listening on port %d", listenPort);

    while (loom_socketId_t acceptedSocket = loom_net_acceptTCPSocket(gListenSocket))
    {
        // Check to see if we got anybody...
        if (!acceptedSocket || ((int)(long)acceptedSocket == -1))
        {
            // Process the connections.
            loom_mutex_lock(gActiveSocketsMutex);
            
            for (UTsize i = 0; i < gActiveHandlers.size(); i++)
            {
                AssetProtocolHandler* aph = gActiveHandlers[i];
                aph->process();

                // Check for ping timeout
                int msSincePing = loom_readTimer(aph->lastActiveTime);
                if (msSincePing > socketPingTimeoutMs)
                {
                    gActiveHandlers.erase(i);
                    i--;
                    lmLog(gAssetAgentLogGroup, "Client timed out (%x)", aph->socket);
                    loom_net_closeTCPSocket(aph->socket);
                    lmDelete(NULL, aph);
                }
            }

            loom_mutex_unlock(gActiveSocketsMutex);

            loom_thread_sleep(10);
            continue;
        }

        lmLog(gAssetAgentLogGroup, "Client connected (%x)", acceptedSocket);

        loom_mutex_lock(gActiveSocketsMutex);
        gActiveHandlers.push_back(lmNew(NULL) AssetProtocolHandler(acceptedSocket));

        AssetProtocolHandler *handler = gActiveHandlers.back();
        handler->registerListener(lmNew(NULL) TelemetryListener());
        if (TelemetryServer::isRunning()) handler->sendCommand("telemetryEnable");

        // Send it all of our files.
        // postAllFiles(gActiveHandlers[gActiveHandlers.size()-1]->getId());

        loom_mutex_unlock(gActiveSocketsMutex);
    }

    return 0;
}
Esempio n. 3
0
// Take a difference report from compareFileEntries and issue appropriate
// file modification notes, and check whether they have settled. If so,
// transmit updates to clients.
static void processFileEntryDeltas(utArray<FileEntryDelta> *deltas)
{
    int curTime = platform_getMilliseconds();

    loom_mutex_lock(gFileScannerLock);

    // Update the pending list with all the stuff we've seen.
    for (UTsize i = 0; i < deltas->size(); i++)
    {
        // Get the delta.
        const FileEntryDelta& fed = deltas->at(i);

        // If it's removal, we don't currently send a notification.
        if (fed.action == FileEntryDelta::Removed)
        {
            continue;
        }

        // If it's not whitelisted, ignore it.
        if (!checkInWhitelist(fed.path))
        {
            continue;
        }

        // Note it in the pending modification list.
        bool sawInList = false;
        for (UTsize i = 0; i < gPendingModifications.size(); i++)
        {
            FileModificationNote& fmn = gPendingModifications.at(i);
            if (strcmp(fmn.path, fed.path.c_str()))
            {
                continue;
            }

            // Match - update time.
            lmLogDebug(gAssetAgentLogGroup, "FILE CHANGING - '%s'", fed.path.c_str());
            fmn.lastSeenTime = curTime;
            sawInList        = true;
        }

        if (!sawInList)
        {
            FileModificationNote fmn;
            fmn.path         = stringtable_insert(fed.path.c_str());
            fmn.lastSeenTime = curTime;
            gPendingModifications.push_back(fmn);
            lmLogDebug(gAssetAgentLogGroup, "FILE CHANGED  - '%s'", fed.path.c_str());
        }
    }

    // Now, walk the pending list and send everyone who hasn't been touched for the settling period.

    // See how many files we're sending and note that state.
    const int settleTimeMs = 750;

    int transferStartTime     = platform_getMilliseconds();
    int totalPendingTransfers = 0;
    for (UTsize i = 0; i < gPendingModifications.size(); i++)
    {
        // Only consider pending items that have aged out.
        FileModificationNote& fmn = gPendingModifications.at(i);
        if (curTime - fmn.lastSeenTime < settleTimeMs)
        {
            continue;
        }

        totalPendingTransfers++;
    }

    bool didWeNotifyUserAboutPending = false;

    for (UTsize i = 0; i < gPendingModifications.size(); i++)
    {
        // Only consider pending items that have aged out.
        FileModificationNote& fmn = gPendingModifications.at(i);
        if (curTime - fmn.lastSeenTime < settleTimeMs)
        {
            continue;
        }

        // Make the path canonical.
        utString filename = fmn.path;
        char     canonicalFile[MAXPATHLEN];
        makeAssetPathCanonical(filename.c_str(), canonicalFile);

        // Note: we don't deal with deleted files properly (by uploading new state) because realpath
        // only works right when the file exists. So we just skip doing anything about it.
        // Note we are using gActiveHandlers.size() outside of a lock, but this is ok as it's a word.
        if ((strstr(canonicalFile, ".loom") || strstr(canonicalFile, ".ls")) && (gActiveHandlers.size() > 0))
        {
            lmLog(gAssetAgentLogGroup, "Changed '%s'", canonicalFile);
        }

        if (canonicalFile[0] == 0)
        {
            lmLog(gAssetAgentLogGroup, "   o Ignoring file missing from the asset folder!");

            // Remove from the pending list.
            gPendingModifications.erase(i);
            i--;

            continue;
        }

        // Queue the callback.
        enqueueFileChangeCallback(canonicalFile);

        // Map the file.
        void *fileBits      = NULL;
        long fileBitsLength = 0;
        if (!platform_mapFile(canonicalFile, &fileBits, &fileBitsLength))
        {
            lmLog(gAssetAgentLogGroup, "   o Skipping due to file failing to map.");
            continue;
        }

        // Loop over the active sockets.
        loom_mutex_lock(gActiveSocketsMutex);

        // Blast it out to all clients.
        for (UTsize j = 0; j < gActiveHandlers.size(); j++)
        {
            // If it's for a specific client then only send to that client.
            if ((fmn.onlyForClient != -1) && (fmn.onlyForClient != gActiveHandlers[j]->getId()))
            {
                continue;
            }

            gActiveHandlers[j]->sendFile(canonicalFile, fileBits, fileBitsLength, totalPendingTransfers);

            // If it has been more than a second, note that we are still working.
            const int remainingTransferCount = (totalPendingTransfers * gActiveHandlers.size()) - j;
            if (((platform_getMilliseconds() - transferStartTime) > 2000) && (remainingTransferCount > 1))
            {
                transferStartTime = platform_getMilliseconds();
                lmLog(gAssetAgentLogGroup, "Still transferring files. %d to go!", remainingTransferCount - 1);
                didWeNotifyUserAboutPending = true;
            }
        }

        loom_mutex_unlock(gActiveSocketsMutex);

        totalPendingTransfers--;

        // Unmap the file.
        platform_unmapFile(fileBits);

        // Remove from the pending list.
        gPendingModifications.erase(i);
        i--;
    }

    loom_mutex_unlock(gFileScannerLock);

    if (didWeNotifyUserAboutPending)
    {
        lmLog(gAssetAgentLogGroup, "Done transferring files!");
    }
}