Jump to content

Lars Fosdal

Administrators
  • Content Count

    3522
  • Joined

  • Last visited

  • Days Won

    116

Posts posted by Lars Fosdal


  1. Do you get a monolithic collection of json elements for the entire day, or do they arrive one by one?

    If monolithic, you could split it up and add each element to a queue.


    Is there a sequence of processing requirement?

    If not, you could have multiple parallell consumers of that queue.

    • Thanks 1

  2. Found a description of "Invalid audience"-here
    https://stackoverflow.com/questions/75228773/access-token-validation-failure-invalid-audience-office-365-graph-api

    Spelunked and found this, but haven't tried it myself
    https://github.com/jfbilodeau/AzureRESTExample

     

    There also is this thread, but I am uncertain if it came to conclusion?

     

    OAuth2 isn't really a standard, but a guideline, and there can be fickle differences between implementations.

    I successfully do OAuth2 authentication to our ERP systems, using System.Net.HTTPClient THTTPClient, and simulating a form post.
    I couldn't get the REST OAuth component to work.

     

    In the source below, TRes is a TObject containing the properties of the expected response body from the authentication - which should contain your tokens.

     

    function TIONAPI.BuildStringStream(const NameValues: TNetHeaders): TStringStream;
    var
      Encoded, Sep : string;
    begin
      Sep := '';
      Encoded := '';
      for var item in NameValues
      do begin
        Encoded := Encoded + Sep + Item.Name + '=' + Encoder.EncodeForm(Item.Value);
        Sep := '&';
      end;
      Result := TStringStream.Create(UTF8String(Encoded));
    end;
    
    function TIONAPI.PostForm<TRes>(const aURL: string; const aFormFields: TNetHeaders; aExpectsResult: Boolean): TRes;
    var
      HTTPRequest: IHttpRequest;
      HttpResponse: IHttpResponse;
      ReqBody: TStringStream;
      ResStatus: Integer;
      ResContent: string;
      ReqHeaders: TNetHeaders;
      T: TStopWatch;
    begin
      Result := nil;
      ResStatus := 0;
      ReqBody := nil;
      FLastStatus := 0;
      FLastErrorMsg := '';
    
      try
        try
          DebugOut(Format('HTTP %s %s', ['POST', aURL])); // DO NOT TRANSLATE
          try
            HTTPRequest := HTTP.GetRequest('POST', aURL);
            HTTPRequest.RemoveHeader('User-Agent');
    
            HTTPRequest.SetCredential(IONCredentials.ResourceOwnerClientId, IONCredentials.ResourceOwnerClientSecret);
    
            ReqBody := BuildStringStream(aFormFields);
            HttpRequest.SourceStream := ReqBody;
    
            ReqHeaders := [
              TNetHeader.Create('content-type', mime.ApplicationXwwwForm),        // DO NOT TRANSLATE
              TNetHeader.Create('Expect', '100-continue')                         // DO NOT TRANSLATE
    //          TNetHeader.Create('User-Agent', UserAgent);             // DO NOT TRANSLATE
            ];
    
            HTTP.PreemptiveAuthentication := True;
    
            T := TStopWatch.StartNew;
            HttpResponse := HTTP.Execute(HTTPRequest, nil, ReqHeaders);
            T.Stop;
            DebugOut('Status: ' + ResStatus.ToString + ' in ' + T.ElapsedMilliseconds.ToString+ ' ms');
    
            if Assigned(HttpResponse)
            then begin
              ResStatus := HttpResponse.StatusCode;
              ResContent := HttpResponse.ContentAsString(TEncoding.UTF8);
              if (ResStatus = 200)
              then begin
                try
                  T := TStopWatch.StartNew;
                  Result := TJson.JsonToObject<TRes>(ResContent);
                except
                  on E: Exception
                  do begin
                    DebugOutException(E,
                      Format('TIONAPI.PostForm.%s<%s, %s> returned StatusCode: %d - but failed during conversion of "%s"', // DO NOT TRANSLATE
                      [aURL, '', Result.ClassName, ResStatus, ResContent]));
                    ResStatus := HTTPStatus.ExpectationFailed417;
                    Result := nil;
                    FLastErrorMsg := E.Message;
                  end;
                end;
              end
              else begin
                Result := nil;
              end;
            end
            else begin
              ResStatus := HTTPStatus.NoResponse;
              ResContent := '';
              Result := nil;
            end;
    
          except // Json Exception
            on E:Exception
            do begin
              DebugOutException(E);
              ResStatus := HTTPStatus.ExpectationFailed417;
            end;
          end;
    
        finally
    //      DebugOut('Status: ' + ResStatus.ToString);
          ReqBody.Free;
        end;
      except // HTTP Exception
        on E: Exception
        do begin
          FLastStatus := ResStatus;
          FLastErrorMsg := E.Message;
          DebugOutException(E, Self.ClassName + '.PostForm'); // DO NOT TRANSLATE
        end;
      end;
    end;

     


  3. I find some of the EMBT marketing practices to be idiotic and unnecessary.

     

    They keep spamming me these offers for "upgrades" and "new licenses" with varying levels of price slashing, all year around.

    Don't they consider that I have been a subscriber for more than a decade, and that the offers only are valid for new licenses?

     

    The new releases and offers tend to bundle some third party tool or package that is underfunctional and overpriced,

    and where the license terms are a tad unclear after the year has passed. After being bought by Idera, it is often some other

    Idera purchased product that I have little interest in. I find the bundling practices to be inconsistant, to put it mildly.

     

    Not only do they do this directly, but the local representative also spam the same offers, over and over.

    According to the local representative - it is EMBT that do the spam on their behalf.


    image.thumb.png.fb43dbc01657f02ba704d4a191f46928.pngimage.thumb.png.9cafb1e7ccfb1c50a705d00621224191.png

     

    Where is the reward for staying a long time paying customer? It is not like the maintenance is cheap, and it is not like I spam EMBT with support issues. 

    As for support, I don't think I've every raised a support question apart from the annoying license counter bump requests.

     

    Ok, I am paying for new versions, updates, hotfixes, etc. - but to be honest, for many major versions now, the first  xx.0 releases have of sub-par quality.

    We've had to wait at least for update 1, and a hotfix or two - before it was fit for use.

     

    About license management... Remember the Delphi .NET craze? It led us to purchase RAD Studio licenses to get a the new and shiny .NET stuff. That shit didn't last long, mostly due to MS not fully opening the door on third party .NET tools - but - when they were discontinued, we were still on RAD Studio Enterprise, when we really only need Delphi Enterprise. We have never used the C++ part of RAD Studio., but there is no way to downgrade a license, and it is still cheaper to keep the RAD Studio Enterprise maintenance, than to repurchase Delphi Enterprise licenses.

     

    So we stay on maintenance and keep hoping for

    • Old problems to be fixed
    • New platforms to be supported
    • HighDPI to be done right
    • Code performance to be improved
    • RTL performance to be improved
    • IDE to become stable and performant
    • Debuggers that actually work in all scenarios
    • Less immature and unfinished new libs and components
    • Less pointless marketing offers

    because, warts and all, the tool is what we have become dependant on.

     

    Still hoping that it will change for the better...

     

    http://www.toodarkpark.org/computers/humor/shoot-self-in-foot.html

    C++: You accidentally create a dozen instances of yourself and shoot them all in the foot. Providing emergency medical assistance is impossible since you can’t tell which are bitwise copies and which are just pointing at others and saying, “That’s me, over there.”

    Delphi: You try to shoot yourself in the foot but discover that the bullets you already had are not compatible with the new gun version, but Borland promises a fix real soon now.

    Assembly: You try to shoot yourself in the foot only to discover that you must first invent the gun, the bullet, the trigger, and your foot.

    • You crash the OS and overwrite the root disk. The system administrator arrives and shoots you in the foot. After a moment of contemplation, the system administrator shoots himself in the foot and then hops around the room rapidly shooting at everyone in sight.
    • By the time you’ve written the gun, you are dead, and don’t have to worry about shooting your feet. Alternatively, you shoot and miss, but don’t notice.
    • Using only 7 bytes of code, you blow off your entire leg in only 2 CPU clock ticks.
    • Like 3
    • Haha 1

  4. @Willicious  A common challenge when updating UI components that have events of their own, is that setting values in the component, will trigger said events, which again trigger your event handlers, which then exec code that changes other UI elements.  Do you take steps to ensure that you don't get a flurry of events between different parts of the UI and biz logic when you change data in the components?

×