/** * Adds a command to be processed. The service guarantees that * all added commands will be processed and any response handler will * always be called regardless of if previous commands experience * errors. Furthermore added commands will always be executed in the * order they were added. * <p> * Note that adding commands using this method is equivalent to * registering a process commands callback and adding commands * when the process commands callback is made. This means that any * callbacks already registered will be executed before the command * (or commands if the delayProcessing flag is used) added using this * method. * <p> * Example: Adding commands A, B, and C with delayProcessing set to * true for A and B, but false for C will be equivalent to register a * callback and add A, B, and C when the callback is made. * * @param command The command to add. * * @param handler Optional. If specified, this is * a callback that will be called when the command has been * processed. The object passed in the callback can be used to check * if the command succeeded and to access any returned data. * * @param stateData Optional. The state data to use. If null or omitted * the default state data will be used as specified in the constructor. * * @param delayProcessing Optional. A hint that tells the service not to try to send the * command immediately. This hint is useful when adding a sequence * of commands in one go. Specifying this flag to true for all * commands except the last one added will ensure that the Service * don't start processing the events immediately, but holds * processing until the last command in the sequence has been added. **/ public void AddCommand(IRSCommand command, ResponseHandler handler, RSStateData stateData = null, bool delayProcessing = false) { if (stateData == null) { stateData = DefaultStateData; } lock (callbackQueue) { if (currentServiceCallback == null) { currentServiceCallback = new RSCommandSequence(this, stateData); } else if (currentServiceCallback.StateData != stateData) { AddCommandSequence(currentServiceCallback); currentServiceCallback = new RSCommandSequence(this, stateData); } currentServiceCallback.AddCommand(command, handler); if (!delayProcessing) { AddCommandSequence(currentServiceCallback); currentServiceCallback = null; } } }
public RSCommandSequence(RSService service, RSStateData stateData = null) { Service = service; StateData = stateData; ContainsRenderCommands = false; ContainsResponseHandlers = false; }
/** * Creates the application and user scopes and imports the scene into the user scope. * Also gets the bounding box. */ public void ImportScene() { InitValues(); Status("info", "Importing scene"); Service.AddCallback((RSCommandSequence seq) => { seq.AddCommand(new RSCommand("create_scope", "scope_name", "app_scope" )); seq.AddCommand(new RSCommand("create_scope", "scope_name", UserScope, "parent_scope", "app_scope" )); seq.AddCommand(new RSCommand("use_scope", "scope_name", UserScope )); seq.AddCommand(new RSCommand("import_scene", "block", true, "scene_name", Filename, "filename", Filename ), OnSceneImport); seq.AddCommand(new RSCommand("scene_get_bounding_box", "scene_name", Filename ), OnSceneGetBoundingBox); seq.AddCommand(new RSCommand("echo", "input", "pre_app_init" ), (RSResponse resp) => { OnApplicationInit(); }); // All commands after this point will be done in the user scope. RSStateData defaultState = new RSStateData(); defaultState.StateCommands.Add(new RSCommand("use_scope", "scope_name", UserScope )); Service.DefaultStateData = defaultState; }); }
/** * <p>Adds a callback to the end of the callback queue. The callback * will be made at the point in time when the service is ready to * process commands generated by this callback. Callbacks will * always be made in the order they were registered with the * service, so if callback A is added before callback B, then A * will be called before B and consequently any commands added by * A will be processed before any commands added by B.</p> * * <p>Callbacks are one-shot, meaning that a callback needs to be * registered every time the application needs to process commands. * The same callback can only be registered once at a time. The * application is responsible for keeping track of any user input * that occurs while waiting for the callback and convert that * user input into an optimized sequence of NWS commands. The same * callback function can be added again as soon as it has been * called or cancelled.</p> * * <p>NOTE: When the callback is made the supplied RSCommandSequence * instance must be used to add the commands, not RSService.AddCommand().</p> * * @param callback The callback. The callback function will be called with a * single argument which is the RSCommandSequence to which commands should be * added using the AddCommand(command, responseHandler) method. * * @param stateData Optional. The state data to use. If null or omitted * the default state data will be used as specified in the constructor. * * @param delayProcessing Optional. This flag instructs the * service if it should delay processing of the added callback or not. * Defaults to false which is recommended in most cases. */ public void AddCallback(SequenceHandler handler, RSStateData stateData = null, bool delayProcessing = false) { if (handler == null) { return; } if (stateData == null) { stateData = DefaultStateData; } bool found = false; lock (callbackQueue) { foreach (CallbackWrapper wrapper in callbackQueue) { if (wrapper.Callback == handler) { found = true; break; } } if (!found) { callbackQueue.Enqueue(new CallbackWrapper(handler, stateData)); } } if (!delayProcessing) { ProcessCallbacks(); } }
public CallbackWrapper(SequenceHandler callback, RSStateData stateData) { Callback = callback; StateData = stateData; }