3 Replies Latest reply on Apr 22, 2015 9:56 PM by Jon Tara

    API (extension) instance enumeration

    Jon Tara

      I am struggling to understand the intended use and implementation of enumeration of API instances. In particular, I am interested in understanding it in the context of Rhodes native extensions. However, the same code structure is used in (many of) the internal APIs.


      With the exception of Camera, all of the enumeration implementations seem to be dummied-up. Some will enumerate only one instance, regardless of how many there actually are. some will arbitrarily enumerate two instances.  And it is only implemented for iOS, where the enumerated values can be "back" or "front".


      I'm also confused that all this really is enumerating is some strings that might symbolically identify instances.


      I don't understand how/where to generate instance IDs for additional instances. Is there some assumption that you have a number at the tail of the string, and there is some base class code that will increment the number?


      This seems like unfinished code, perhaps an idea that was never implemented?


      FWIW, the extension I am creating is a Factory-style extension with a default instance. It's a Bonjour Browser extension. It's handy to have a default instance, but it might also be useful to have multiple instances. (For example, you might do multiple simultaneous searches for different services. Or you might not use them simultaneously, but it might be convenient to leave multiple browser objects laying around for use.)


      A side-effect of enumeration might be useful to me, but is not essential. I make use of the ID value, because the extension has callbacks, and it's handy to include the ID value in each callback. That way, application code can choose to either send callbacks from each instance to a different controller URL (or lambda function) or all to the same. So, the callback code has a way of distinguishing instances in the callbacks.


      I haven't actually tried creating a non-default instance yet. But, if I read the code correctly, as I have it currently written, the ID value will be nil for all but the default instance:


      #import "BonjourBrowserSingleton.h"
      @implementation BonjourBrowserSingleton
      -(NSString*)getInitialDefaultID {
          return @"BonjourBrowser1";
      -(void) enumerate:(id<IMethodResult>)methodResult {
          NSMutableArray* ar = [NSMutableArray arrayWithCapacity:1];
          [ar addObject:@"BonjourBrowser1"];
          [methodResult setResult:ar];


      Most of the Rhodes APIs arbitrary return an array with "SCN1" and "SCN2". That's clearly not correct.


      So, I get the idea that enumerate ought to return an array with the ID strings of the instances that exist? Is application code supposed to be able to change the IDs? The ID is an API property (that we don't have to declare in our XML) so, in instance initialization, set the value of the ID property? (So that is where you would implement generation of IDs...) Then I would have to keep track of instances in some data structure (probably a hash/dictionary/etc.) in a class variable?


      I checked the current master, and there doesn't seem to be any significant difference. I only find this dead-end half-implemented code.


      Maybe I am misunderstanding intent, and this doesn't really apply to my scenario, as it seems oriented toward enumerating multiple hardware feature instances. (Such as cameras).


      I don't really have a use for the enumeration in my code, but I do have a use for the IDs. And, perhaps that is the answer. I should generate a unique ID when an instance is created, but enumerate will "enumerate" only the default instance.

        • Re: API (extension) instance enumeration
          Jon Tara

          Now even more confused...


          Common API usage for Ruby is described here:


          Rhomobile | Using RhoMobile Ruby API&rsquo;s


          Of course, the example shown is bogus, because (as of 5.0.30) the Camera API is still a 2.2 API... (I believe it is a Common API in 5.1, right?)


          The implication from this is that enumerate should return an object. But, clearly, the code currently implemented for all of the common APIs enumerates the string IDs, not any kind of object. Maybe there is some magic I am missing. How do we get from those ID strings to actual Ruby/Javascript objects? The example proceeds to attempt to call a method. take_picture on the returned object. That clearly can't work if what enumerate returns is the string, "front"...


          Does enumeration actually work? I mean, as documented?


          I do see, at least from the Camera example, that the purpose of enumeration seems to be to enumerate hardware assets of some particular class handled by an API. And, so, probably has no role in my Bonjour Browser code. It would be strange (though perhaps of some utility) to be able to enumerate API object instances created by application code...


          It seems like unfinished code/loose ends.

            • Re: Re: API (extension) instance enumeration
              Jon Tara

              OK, I have this figured-out! At least mostly...


              I deduced to go ahead and actually try instantiating a second browser object, and see what happens. I'm guessing that there IS some "magic" going on here with the IDs. I ran two of my Bonjour Browsers simultaneously, and since I log the instance IDs, that told me what is going on here.


              This is a controller method I used for test. It's run when you push a button on the Settings page.


                def bonjour_browser_search
                  # Note: default service type is '_http._tcp_.', default domain is '.local'
                  # This will find all local web servers that are advertising
                  Rho::BonjourBrowser.search({}, lambda do |callback_data|
                      {{#logInfo}} "got callback from Rho::BonjourBrowser.search callback_data = #{callback_data.inspect}" {{/logInfo}}
                    end # lambda
                  # Get two browsers going at once as a test
                  meta_browser = Rho::BonjourBrowser.new
                    meta_browser.search({serviceType: Rho::BonjourBrowser::SERVICE_TYPE_META_QUERY}, lambda do |callback_data|
                      {{#logInfo}} "got callback from meta_browser.search callback_data = #{callback_data.inspect}" {{/logInfo}}
                    end # lambda


              The initial default ID and enumerate do indeed seem to be about the default instance(s). That (s) points-out an omission in the documentation. Depending on the API, there might be one OR MORE default instances! Makes sense for hardware devices.


              So, the (non-existant, at least in 5.0.30...) new, (common API) Camera API might allow you to enumerate the camera assets on the device. In this case, there isn't a "default instance", but "default instances".


              That code doesn't seem to come into play at all for instances that you create. In that case, the ID is set to a hex string that looks suspiciously like a memory address.


              It's a bit ironic, since my API deals with some objects (service instances) it creates internally (in Objective-C) and I give those IDs as well, and include those IDs in the callbacks. (They can be used as "handles" in method calls to do something with a service instance.) I thought it a bad idea to return string-encoded addresses, and so I took the extra step to assign sequential IDs instead...


              A callback example from the default instance:


              2015-04-22 21:21:32.679 rhorunner[20191:994029] I 04/22/2015 21:21:32:679 5d6d7000           HttpServer| Process URI: '/system/call_ruby_proc_callback'

              2015-04-22 21:21:32.679 rhorunner[20191:994029] I 04/22/2015 21:21:32:679 5d6d7000                  APP| Params: {"__rho_object"=>{"body"=>"2"}, "rho_callback"=>"1"}

              2015-04-22 21:21:32.680 rhorunner[20191:994029] I 04/22/2015 21:21:32:679 5d6d7000   SettingsController| [block in bonjour_browser_search](39) got callback from Rho::BonjourBrowser.search callback_data = {"searching"=>true, "port"=>80, "hostName"=>"colossus.local.", "API"=>"BonjourBrowser", "addresses"=>[{"address"=>"", "port"=>80, "family"=>"ipv4"}, {"address"=>"fe80::215:f2ff:fed3:1e35", "port"=>80, "scopeID"=>4, "flowInfo"=>0, "family"=>"ipv6"}], "event"=>"didResolve", "resolved"=>true, "serviceID"=>"BonjourBrowser1-4", "serviceName"=>"Apache Web Server on colossus", "ID"=>"BonjourBrowser1", "resolving"=>false}



              And one from the instance I created:


              2015-04-22 21:21:53.376 rhorunner[20191:994029] I 04/22/2015 21:21:53:376 5d6d7000           HttpServer| Process URI: '/system/call_ruby_proc_callback'

              2015-04-22 21:21:53.377 rhorunner[20191:994029] I 04/22/2015 21:21:53:377 5d6d7000                  APP| Params: {"__rho_object"=>{"body"=>"2"}, "rho_callback"=>"1"}

              2015-04-22 21:21:53.377 rhorunner[20191:994029] I 04/22/2015 21:21:53:377 5d6d7000   SettingsController| [block in bonjour_browser_search](47) got callback from meta_browser.search callback_data = {"searching"=>true, "moreComing"=>false, "API"=>"BonjourBrowser", "event"=>"didFindService", "resolved"=>false, "serviceID"=>"EF0159A8-21", "serviceName"=>"_apple-mobdev2", "ID"=>"EF0159A8", "resolving"=>false}


              I think it make sense for this API to set the default instance ID to "default". Then, enumerating will return the single instance with ID "default".


              I dunno what's going on with many of the APIs returning two instances SCN1 and SCN2. That seems bogus to me. Most of these APIs clearly have only a single default instance.


              I'll test if Rhodes magically returns an actual object if I enumerate them (it).