Jump to content

Yaron

Members
  • Content Count

    275
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Yaron


  1. I recently upgrade my main development machine from Windows 7 to Windows 10.

     

    The major thing I noticed is that executing my app under the debugger is slower and file access (on an SSD drive) also seems impacted even though benchmarks show that read/write/io speeds are identical to Windows 7.

     

    Is this something anyone else encountered and possibly found a solution?


  2. What is the best approach you would recommend for creating log files with output to multiple files and input coming from multiple threads (some threads writing into the same log file) with a volume that can reach 1000's of entries per second?

     

    Everything is running in a single process, so Critical section locks can be used and log entries must be flushed so they won't be lost in RAM if the process crashes.


  3. I prepared to post a question on how I can do this, but I actually reached a solution on my own while contemplating on how to best phrase the question and code.

     

    Since I searched and couldn't find good documentation on how to do this, I decided to post my solution here:

     

    Imagine a table with columns: NAME , TAGS , etc ...

    The TAGS column contains a string with multiple unique identifiers, for example "tag0001|tag0002|tag0003|tag0004".

     

    I'm only getting rows with a TAGS column that contains a sub-string I'm looking for (a specific tag) :

       sTAGUID := 'tag0002';
       dbQuery.SQL.Text := 'SELECT * FROM CARDS_TABLE WHERE (POSITION(:taguid,TAGS) > 0) ORDER BY LOWER(NAME) ASC;';
       Try
         dbQuery.Prepare;
         dbQuery.ParamByName('taguid').AsString := sTAGUID;
         dbQuery.Open;
         If dbQuery.RecordCount > 0 then While dbQuery.Eof = False do
         Begin
           New(nEntry);
           ExtractCardQuery(dbQuery,nEntry^);
           cardList.Add(nEntry);
           dbQuery.Next;
         End;
       finally
         dbQuery.free
       end;

     


  4. I would like to integrate Ad support for my Delphi 7 desktop application (I also have Delphi 10.3.3 which I could possibly use to create a DLL which would integrate into the D7 app).

     

    Has anyone here ever create a Delphi desktop app that's supported by advertising?

    This model is very prevalent in the mobile world, but on the desktop, I haven't found a lot of information.

     

    I could easily integrate google ads, but I believe they do not allow ads within desktop applications.

    Microsoft seems to allow Ads (https://developer.microsoft.com/en-us/store/monetize/ads-in-apps), but the API is designed for UWP apps (am I mistaken?) and I'm not sure how to go about the integration process.

    Do you suggest other Ad networks that would integrate nicely with Delphi?


  5. Using Delphi 10.3.3:

    My goal is to have a stable client/server remote control over TCP/IP that can automatically recover in cases where the network disconnects occasionally.

     

    I use a structure Remi suggested of creating a reading thread that tries to readln with a 1sec time out:

        FClient.OnDisconnected := OnDisconnect;
        FClient.IOHandler.ReadTimeout := 1000; // lets us exit the read operation after 1sec of inactivity
    
        While Terminated = False do
        Begin
          If FClient.Connected = True then
          Try
            FData := FClient.IOHandler.ReadLn(IndyTextEncoding_UTF8);
          Except
            // catch exception & update UI
            Try
              If FClient.Connected = True then FClient.Disconnect;
            except
              on E: Exception do
              Begin
                // Catch disconnect exception
              End;
            end;
          End;
        End;  

    I have a client PC connected to a router via cable and the server PC connected to the same router via WiFi.

     

    After connecting the client to the server, I disconnect the server's wifi access and absolutely nothing happens (I waited over a minute).

    The OnDisconnected event isn't triggered, calling FClient.IOHandler.ReadLn doesn't return any exception and FClient.Connected remains True.

     

    If I then try to call FClient.IOHandler.WriteLn, within about 10 seconds a "Socket Error # 10054 - Connection reset by peer" exception is raised on the ReadLn code about (not on the WriteLn function).

    In that exception, I call "If FClient.Connected = True then FClient.Disconnect" which raises another "Socket Error # 10054 - Connection reset by peer" exception.

    Finally, my code loops to the beginning and then the same exception is triggered on the initial "If FClient.Connected = True" line.

     

    Obviously, I'm not handling things correctly, I wasn't expecting "If FClient.Connected" to raise exceptions and I was hoping the OnDisconnect event to trigger, but are there other pitfalls I might be missing?


  6. On Android, RTL text (e.g. Hebrew) appears in reverse order (letter order is reversed).

    Using the same code, & input (YouTube DATA API 3) and the text appears correctly in windows.

     

    I searched the web and the only reference I was able to find is a post from five years ago that says RTL is not supported and there is no roadmap entry for future support:

    https://stackoverflow.com/questions/28494354/right-to-left-language-in-delphi-xe7-mobile-android

     

    Has anything changed since?


  7. For some reason, even when setting the TListView's control to not show the "Details" section, the text within the control is cut at about 80% of the width.

     

    I have "ListView.ItemAppearanceObject.ItemObjects.Detail.Visible = False" and "ListView.ItemAppearanceObject.ItemEditObjects.Detail.Visible = False".

    And "ListView.ItemAppearance" set to "ListItem" (which adds a ">" at the end of the line for some reason).

     


  8. I am sharing a video's URL from YouTube to my Android app.

     

    I do this using Android Intents by modifying the "AndroidManifest.template.xml", adding:

    <intent-filter>  
      <action android:name="android.intent.action.SEND" />
      <category android:name="android.intent.category.DEFAULT" />
      <data android:mimeType="text/plain" />
    </intent-filter>

     

    Then in my app's form OnCreate event, I use:

      if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, AppEventService) then
        AppEventService.SetApplicationEventHandler(HandleAppEvent);
    
      MainActivity.registerIntentAction(TJIntent.JavaClass.ACTION_SEND);
      TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedNotification, HandleActivityMessage);

    Then HandleAppEvent looks like this:

    function TMainForm.HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean;
    var
      StartupIntent: JIntent;
    begin
      Result := False;
      Case AAppEvent of
        TApplicationEvent.BecameActive:
        Begin
          clientAndroidBecameActive := True;
          If clientAndroidActivated = False then
          Begin
            clientAndroidActivated := True;
            StartupIntent := MainActivity.getIntent;
            if StartupIntent <> nil then
            Begin
              HandleIntentAction(StartupIntent);
              StartupIntent := nil;
            End;
          End;
        End;
      end;
    end;

    And HandleActivityMessage looks like:

    procedure TMainForm.HandleActivityMessage(const Sender: TObject; const M: TMessage);
    begin
      if M is TMessageReceivedNotification then HandleIntentAction(TMessageReceivedNotification(M).Value);
    end;

    And finally, HandleIntentAction:

    function TMainForm.HandleIntentAction(const Data: JIntent): Boolean;
    var
      Extras : JBundle;
      sURL   : String;
    begin
      Result := False;
      if Data <> nil then
      begin
        Extras := Data.getExtras;
        if Extras <> nil then
        Begin
          sURL := JStringToString(Extras.getString(TJIntent.JavaClass.EXTRA_TEXT));
          // Do something useful with the URL
          Extras := nil;
        End
      end
    end;

    My problem is there are occasions after sharing where an intent is duplicated, triggering once on the share and again when opening the app later on.

     

    Does anyone have experience with something similar?

     

     


  9. If anyone else is wondering how it's done, you need to add "[Context] marsRequest: TWebRequest;" and then the client's IP is available in "marsRequest.RemoteIP".

      [Path('projectX')]
      TProjectXServicesResource = class
      protected
        [Context] marsRequest: TWebRequest;
      public
        [GET, Produces(TMediaType.TEXT_HTML)]
        function xHome([QueryParam] lang : String) : String;
    
        [POST, Consumes(TMediaType.MULTIPART_FORM_DATA), Produces(TMediaType.TEXT_HTML)]
        function xAction([FormParams] AParams: TArray<TFormParam>): String;
      end;
    
    function TProjectXServicesResource.xHome([QueryParam] lang : String) : String;
    begin
      ShowMessage(marsRequest.RemoteIP);
    end;
    
    function TProjectXServicesResource.xAction([FormParams] AParams: TArray<TFormParam>) : String;
    begin
      ShowMessage(marsRequest.RemoteIP);
    end;

     


  10. @David Heffernan It's not that the code freezes forever, it stalls.

     

    Here are real-world examples,

    1. A 3rd party product called ODB Studios has a bug, it does not set a timestamp for it's audio stream, so when playing a video, the entire stream must be decoded to reach the seek point (the position where I take the thumbnail).

    This causes the (directshow) seek command to stall for upto 60 seconds.

     

    2. A user starts to download a video file and then pauses/stops the download (so the file is no longer locked, I postpone thumbnail generation for locked files).

    The video's frame-index block did not download yet, so the (directshow) file parser then scans the entire media file to reconstruct the frame-index which can easily stall for 30-60 seconds on multi-GB files.

     

    There are other cases where this issue can happen, there is no way to avoid it since I can't know in advance every case for every audio/video format that may pop-up.

     

     


  11. I have a usage case where my application scrapes a screenshot (thumbnail) from multiple video files in background threads.

    I grab the screenshot using a third party library.

     

    The problem is sometimes, the third party library will stall, usually due to a corrupt/incomplete media file where it tries to analyze the entire file (which can take upto 30 seconds).

    I have no way to notify the third party library to cease operations.

     

    This stalling can prevent my application from closing (It's waiting for threads to finish so the exit is clean) or even make the UI appear semi-broken because no thumbnails show up.

     

    I'd like to hear what you may have done to handle such cases?


  12. Hi @Andrea Magni

    To improve security and statistics, I need access to the client's IP address when my function triggers in server.resources:

     

      [Path('projectX')]
      TProjectXServicesResource = class
      protected
      public
        [GET, Produces(TMediaType.TEXT_HTML)]
        function xHome([QueryParam] lang : String) : String;
    
        [POST, Consumes(TMediaType.MULTIPART_FORM_DATA), Produces(TMediaType.TEXT_HTML)]
        function xAction([FormParams] AParams: TArray<TFormParam>): String;
      end;
    
    function TProjectXServicesResource.xHome([QueryParam] lang : String) : String;
    begin
      // Need access to the client's IP here
    end;
    
    function TProjectXServicesResource.xAction([FormParams] AParams: TArray<TFormParam>) : String;
    begin
      // Need access to the client's IP here
    end;

    How can I obtain the client IP?


  13. Looks like this issue is somewhat complex, I've actually read this article:
    https://www.the-art-of-web.com/sql/counting-article-views/

     

    In which they suggest creating a separate table just for view counting, with each row representing a view (sql INSERT) and every so often running aggregation code that converts the rows into actual pageview numbers to insert into the original table and erase the counted rows.

    Using this method means no deadlocks are possible when counting things, might even mean less DB overhead (they write that UPDATE is slower than INSERT, but it's not something I confirmed).

     


  14. 59 minutes ago, Zoran Bonuš said:

    Exactly, just what I was about to recommend. You create deadlock because the new value of VIEW_COUNT depends on the old value, and due to the nature of multi-generation architecture a simultaneous transactions, there can be different old values, depending on the isolation settings of your transaction.

    Using generator/sequence for view_count circumvalents the problem for this specific update query. However, a proper transaction setting is preferred anyway. There is no magic solve-it-all setting, I recommend studing the docs too .. will most likely came in handy later anyway.

    I'm a complete novice working with databases and like dany, I want to know how as well.

    I actually tried reading the documentation (https://firebirdsql.org/refdocs/langrefupd25-nextvaluefor.html) but it's pretty alien me at this point.


  15. 22 minutes ago, Dany Marmur said:

    The case above is not quite clear to me. Where do you get the actual value for count?

    IMHO - reading up on FB transaction handling will get you a long way. I think FireDAC has components for that, not sure though.

     

    If you would want to increase the count inside you SQL then deadlocks could definitely happen.

    Two ways to manage that; either handle the case in your Exception block, posting something that will retry the operation. That could prove messy depending on the rest of the application/service architecture.

    The second way is to tell FB that this trasaction should wait for a lock to be released. Now, the message indicates that the transaction is NOT waiting. You set a value of seconds for transaction wait.

     

    I'm not the best to help here since i do not use FireDAC and i have no idea of how to handle transaction parameter, autocommitts and such stuff using FireDAC:

     

    HTH,

     

    /Dany

     

    The view number is read earlier in the code, I actually replaced it with a more reliable SQL command to increase the value instead of setting it:

    procedure ClubHouseDB_IncCampaignViewCount(sDebugFile,sGalleryUID : String);
    var
      dbConn     : TFDConnection;
      dbQuery    : TFDQuery;
      deadLocked : Boolean;
    begin
      deadLocked := False;
      dbConn  := TFDConnection.Create(nil);  dbConn.ConnectionDefName := dbPoolName;
      dbQuery := TFDQuery.Create(nil);       dbQuery.Connection       := dbConn;
      Try
        dbQuery.SQL.Text   := 'UPDATE GALLERY_TABLE SET VIEW_COUNT=VIEW_COUNT+1 WHERE GALLERY_UID=:galleryuid;';
        Try
          dbQuery.Prepare;
          dbQuery.ParamByName('galleryuid').AsString := sGalleryUID;
          dbQuery.ExecSQL;
        Except
          on E : Exception do If Pos('deadlock',Lowercase(E.Message)) > 0 then deadLocked := True;
        End;
      Finally
        dbQuery.Free;
        dbConn.Free;
      End;
      If deadLocked = True then ClubHouseDB_IncCampaignViewCount(sDebugFile,sGalleryUID);
    end;

    As you can see from the updated code, I'm catching the deadlock by looking at the returned exception message, I'm not sure it's the best approach, but I haven't been able to find another way to identify the deadlock.

     

    I don't have a problem increase the deadlock timeout, but I couldn't find anything on how to do that, I'm not even sure if it's part of the Firebird SQL statement or if I need to specify it through the Firedac components.

     


  16. I'm new to databases, is there any Delphi Firedac sample code that shows best practices when handles deadlocks?

     

    My deadlock is a simple integer page-view counter, here's the actual code:

    procedure SetCampaignViewCount(sDebugFile,sGalleryUID : String; nCount : Integer);
    var
      dbConn  : TFDConnection;
      dbQuery : TFDQuery;
    begin
      dbConn  := TFDConnection.Create(nil);  dbConn.ConnectionDefName := dbPoolName;
      dbQuery := TFDQuery.Create(nil);       dbQuery.Connection       := dbConn;
      Try
        dbQuery.SQL.Text   := 'UPDATE GALLERY_TABLE SET VIEW_COUNT=:viewcount WHERE GALLERY_UID=:galleryuid;';
        Try
          dbQuery.Prepare;
          dbQuery.ParamByName('galleryuid').AsString := sGalleryUID;
          dbQuery.ParamByName('viewcount').AsInteger := nCount;
          dbQuery.ExecSQL;
        Except
          on E : Exception do
          Begin
            {$IFDEF TRACEDEBUG}AddDebugEntry(sDebugFile,'SetCampaignViewCount Exception : '+E.Message){$ENDIF};
          End;
        End;
      Finally
        dbQuery.Free; dbConn.Free;
      End;
    end;

     


  17. This happens on a particular project,

     

    Simply opening the project and clicking on "refactor" from the top menu causes the entire IDE to crash with "Embarcadero RAD Studio for Windows has stopped working, A problem caused the program to stop working correctly. Please close the program.".

    The same thing happens if I do "Run -> Step Over" from the top menu followed by clicking the "search" top menu entry.

    In both cases the top menu's pop-up doesn't show up before the crash.

     

    Doesn't happen if I open another project, but can be reliably reproduced on the problematic (larger) project every time.

    Anyone encountered anything like this before?  I'm not even sure how to track down this issue.


  18. 8 minutes ago, rvk said:

    But I see you update the table in the thread. You didn't do that in your original post.

     

    The deadlock can come from using transactions incorrectly (or updating the same record in different transactions/threads),

    http://www.firebirdfaq.org/faq151/

    Thanks, I read the FAQ entry.

    I'm new to working with databases, what is the best approach to deal with deadlocks?

     

    The actual DB call that triggered the deadlock was a view counter, two users viewing the same web page.

    What is the best approach to handle such deadlocks?

     


  19. My code now creates and frees both TFDConnection and TFDQuery:

    procedure DB_SetUserFlags(sDebugFile,sUserUID : String; iFlags : Integer);
    var
      dbConn  : TFDConnection;
      dbQuery : TFDQuery;
    begin
      dbConn := TFDConnection.Create(nil);
      dbConn.ConnectionDefName := dbPoolName;
      dbQuery := TFDQuery.Create(nil);
      dbQuery.Connection := dbConn;
      Try
        dbQuery.SQL.Text   := 'UPDATE USERS SET USER_FLAGS=:userflags WHERE USER_UID=:useruid;';
    
        Try
          dbQuery.Prepare;
          dbQuery.ParamByName('userflags').AsInteger := iFlags;
          dbQuery.ParamByName('useruid').AsString    := sUserUID;
          dbQuery.ExecSQL;
        Except
          on E : Exception do {$IFDEF TRACEDEBUG}AddDebugEntry(sDebugFile,'Exception : '+E.Message){$ENDIF};
        End;
      Finally
        dbQuery.Free;
        dbConn.Free;
      End;
    end;

     


  20. After rewriting every DB entry point using "TFDConnections", I managed to resolve most of the errors, now I'm only receiving these 2:

    Project GameServicesServerApplication.exe raised exception class EIdSocketError with message 'Socket Error # 10053 Software caused connection abort.

    Project GameServicesServerApplication.exe raised exception class EIBNativeException with message '[FireDAC][Phys][FB]deadlock

     

    I'm assuming the first error is due to constant reloads in browser (it only happens in a browser, doesn't happen for me when load-testing using threads).

    However, the "deadlock" exception is an issue, any ideas why it's triggered and how to avoid it?

×