Decoder

Forum Replies Created

Viewing 4 reply threads
  • Author
    Posts
    • #53442
      Decoder
      Participant

      Thanks Kim. By the time you posted this I had figured it out. Good example though.

      In researching this I found the following mime type:

      vnd.android.package-archive

      The reason this is relevant is because my ‘zip’ file is an apk. Which is essentially a zip file, with a custom extension. I didn’t find that mime type in kbmMWCustomHTTPService.pas, procedure TkbmMWHTTPServiceDefinition.SetupStandardMimeTypes.

      Is there a location where it would make sense to add this mime type? I did get it working with the following code:

      Result := HTTPResponseFromFile(‘AppFileDir\AppFile.apk’,’AppFile.apk’);
      SetResponseFileName(‘AppFile.apk’);
      SetResponseMimeType(‘vnd.android.package-archive’);
      SetResponseContentType(‘UTF-8’);

      It seems that Android likes that MimeType ‘more better’ than application/octet-stream.

      Thanks again Kim.

    • #53432
      Decoder
      Participant

      Ok, figured that out, it’s the AMapPath: Boolean = True param in HTTPResponseFromFile that was messing me up.

      Now I get the file, but the client treats it as a web page, even though I’ve specified the content type as responseMimeType:”application/octet-stream”,

      and displays the content of the zip file in the browser view.

      So I guess I’m looking for the param, attribute, call, switch, component, property etc. that tells the request/response mechanism that this is a file, and specifies the file name.

      Been browsing through your demos, but have not found anything that would demonstrate how to do this via a REST request.

      Help!

    • #53431
      Decoder
      Participant

      I found this:

      function HTTPResponseFromFile(const APath:string; const AAsFileName:string; const AMapPath:boolean = true):variant; overload;

      …in the public interface of TkbmMWCustomHTTPService. I added a file pool to my smart service, creating it in the constructor with the service as the owner, and set the properties to match the properties in Demo\FileTransferStress\Server\Unit1.pas, and finally I assigned the file pool component to the smart service’s filepool property.

      The test file store is a linux folder masked 777. When I call the service method, the response I get is:

      “Cant access file:<file path as designated at runtime>”.

      I checked the path, it’s totally valid. What have I missed?

      Thanks.

       

    • #53361
      Decoder
      Participant

      Hi Kim!

      I’ve included code below that illustrates how I coded this process. If I understood you correctly, I’m responsible for freeing the kbmMemTable’s that I create in the methods below, correct?

      Thanks

      [kbmMW_Service(‘name:<myServiceName>, flags:[listed]’)]
      [kbmMW_Rest(‘path:/<myPath>’)]
      TMyService = class(TkbmMWCustomHTTPSmartService)
      private
      FData: TkbmServerData;

      …

      public
      // allergies
      [kbmMW_Rest(‘method:get, path:allergies, anonymousResult:true, responseMimeType:”application/json”‘)]
      function Allergies([kbmMW_Rest(‘value: “$AnInt”, required: true’)] const AnInt: Integer): TkbmMemTable;

      // Pt Chart
      [kbmMW_Rest(‘method:get, path:ptchart, anonymousResult:true,      responseMimeType:”application/json”‘)]
      function PtChart: TPtChart;

      end;

      …

      implementation

      …

      function TMyService.Allergies(const AnInt: Integer): TkbmMemTable;
      begin
      Result := Nil;
      if Authorized then
      Result := FData.Allergies[AnInt];
      end;
      end;

      function TMyService.PtChart: TPtChart;
      begin
      if Authorized then
      begin
      Result := TPtChart.Create;
      Result.Allergies := Allergies(32126);

      …

      end;

      …

      initialization
      kbmMWRegisterKnownClasses([TPtChart]);

       

       

      type
      TkbmServerData = class(TComponent)
      kAllergies: TkbmMemTable;

      …

      private
      …
      function GetAllergies(AnInt: Integer = 0): TkbmMemTable;

      …

      public
      property Allergies[AnInt: Integer]: TkbmMemTable read GetAllergies;

      …

      end;

      …

      implementation

      …

      function TkbmServerData.GetAllergies(AnInt: Integer): TkbmMemTable;
      var
      oraprof: TOraQueryProfile;
      sErrorMsg: AnsiString;
      fldKey,fldAllergies,fldReaction: TField;
      begin
      if AnInt > 0 then
      begin
      if not Assigned(kAllergies) then
      kAllergies := TkbmMemTable.Create(Self);

      oraprof := TOraQueryProfile.Create(Self,FSession,QAllergies,KSQLAllergies);
      oraprof.AddParam(‘FKEY’,otInteger,FKEY);
      QAllergies.Open;

      with kAllergies.FieldDefs.AddFieldDef do
      begin
      Name := ‘1’;
      DataType := ftString;
      end;
      kAllergies.LoadFromDataSet(QAllergies,[mtcpoStructure,mtcpoFieldIndex]);
      Result := kAllergies;
      end;
      end;

       

    • #53349
      Decoder
      Participant

      Thanks Kim –

      In the intervening time between my post and your response, I found the helper and had started to try to work with it. Your timely blog post helped shorten the curve. 🙂

      Just an FYI, in trying to load test a server I run multiple instances of a client app that runs a sequential loop, iterating through the list of available methods and issuing requests/logging responses.

      One of the methods on the server returns a class – converted to JSON of course – that pulls all data from all of the requests. This works well thanks to your excellent design. However I’m sometimes getting memory leak errors when I shut down the server, related to the class.

      I don’t explicitly destroy the class as I read in one of your blog posts that the service handles destruction of classes that are created within it’s domain.

      Here’s the class:

      TPtChart = class
      public
      Allergies: TkbmMemTable;
      HomeMeds: TkbmMemTable;
      LabResults: UnicodeString;
      MDNotes: UnicodeString;
      RadResults: UnicodeString;
      RNNotes: UnicodeString;
      Vitals: TkbmMemTable;
      end;

      Here’s the service method declaration:

      // Pt Chart
      [kbmMW_Rest(‘method:get, path:ptchart, anonymousResult:true, responseMimeType:”application/json”‘)]
      function PtChart: TPtChart;

      Here’s the service method implementation:

      function TWellRESTFunctionsService.PtChart: TPtChart;
      begin
      if Authorized then
      begin
      Result := TPtChart.Create;
      Result.Allergies := Allergies(32126);
      Result.HomeMeds := HomeMeds(27390);
      Result.LabResults := LabResults(27390,’ANDROID’);
      Result.MDNotes := MDNotes(27390,’ANDROID’);
      Result.RadResults := RadResults(32227,’ANDROID’);;
      Result.RNNotes := RNNotes(27390,’ANDROID’);
      Result.Vitals := AllVitals(32126);
      end;
      end;

      This method executes quickly and returns all of the required data without issue. Can you see why this would leak at the server side? Is there more to be done here?

      Thanks.

       

Viewing 4 reply threads