ISISComputingGroup / lewis-ess

Let's write intricate simulators!
GNU General Public License v3.0
21 stars 19 forks source link

What is the correct way to send unsolicited replies based on events ? #297

Open auphofBSF opened 3 years ago

auphofBSF commented 3 years ago

My use case is to simulate a basic serial device over tcp that responds to commands but also sends unsolicited messages

The doc's strings and Readthedocs are great but I feel I am missing something

I am using a TCP Stream Based on Motor Example

I have successfully implemented Cmd's and get the correct responses

I would like to get an unsolicited_reply() from the StreamHandler when the following events happen

  1. a new connection is made to the simulation interface with Telnet Host:Port (no data yet sent from Client) -> Generates a Welcome message
  2. a periodic (Non Regular - random time interval) event happens in the simulated Device subclassing StateMachineDevice and sends an unsolicited_reply to the TCP client, ie simulating a state change through lewis-control device ....
  3. a periodic (regular - fixed time interval) variant of 2.
mattclarke commented 3 years ago

@DominicOram Any ideas/tips for this?

DominicOram commented 3 years ago

Does https://github.com/ess-dmsc/lewis/tree/message_on_init fix point 1? You should be able to add something like the following in your strream interface:

def initial_message(self):
    return b"Hello World"

I'll think about 2 and 3 later today...

auphofBSF commented 3 years ago

Thank you @DominicOram initial_message works well.

With regard to 2&3 I have spent a few hours trying to see how find the current active StreamHandlers from the process method in StateMachineDevice, getting a deeper understanding of lewis but have not been successful yet, so look forward to your thoughts, Thank you again

DominicOram commented 3 years ago

Yh, the issue is that unsolicited_reply is a bit of a hack. The StreamInterface side holds a reference to the device but not the other way round. This means when we've used unsolicited_reply in the past we've ended up putting what should really be device logic into the StreamInterface or we've set the unsolicited reply to just send periodically. I guess the second link solves 3 for you but still isn't elegant.

auphofBSF commented 3 years ago

Selfishly only considering the adapters.stream,

Could device have a legitimate reference to StreamServer and device have method stream_event_message .

Then StreamServer in the process method forwards stream_event_message if it exists to all handler in _accepted_connections in a similar method to your initial_message suggestion

It is then logic in device to decide periodicity or specific condition for generating stream_event_message

StreamInterface by handler can either just forward message by default event_message method or do further processing by overwritting with a event_message method in the custom impementation of StreamInterface

auphofBSF commented 3 years ago

I have explored this in https://github.com/auphofBSF/lewis/tree/wip_297_unsolicited_messages

In principle it works but generates deque errors and eventually crashes the connection. The across thread comms needs addressing

auphofBSF commented 3 years ago

Ok I have fixed the deque and connection trashing issue, tidied up the solution proposed and could do with a review https://github.com/auphofBSF/lewis/tree/wip_297_unsolicited_messages with example now in branch in 836f263

It is achieving what I required but I am sure it needs to be aligned with lewis styling and more deeper understanding I think how the adapters are attached to devices in simulation could be improved.

I have created an example lewis -k lewis.examples simple_eventing_state_device that attempts to demonstrate some of the features that @DominicOram created with initial_message and what I have introduced in this fork.

With a bit more work, some docs, possibly a test or 2 and I think it can be converted to a PR, but before that I would like to get comment

mattclarke commented 3 years ago

Can you create a draft PR please? It makes it a bit easier for us to see what you have done