import trio
import tractor


@tractor.context
async def simple_rpc(

    ctx: tractor.Context,
    data: int,

) -> None:
    '''
    Test a small ping-pong 2-way streaming server.

    '''
    # signal to parent that we're up much like
    # ``trio.TaskStatus.started()``
    await ctx.started(data + 1)

    stream: tractor.MsgStream
    async with ctx.open_stream() as stream:

        count: int = 0
        msg: str
        async for msg in stream:

            assert msg == 'ping'
            await stream.send('pong')
            count += 1

        else:
            assert count == 10


async def main() -> None:
    '''
    Exercise bidirectional streaming with a remote actor.

    '''
    an: tractor.ActorNursery
    async with tractor.open_nursery() as an:

        portal: tractor.Portal = await an.start_actor(
            'rpc_server',
            enable_modules=[__name__],
        )

        # XXX: syntax requires py3.9
        ctx: tractor.Context
        sent: int
        stream: tractor.MsgStream
        async with (

            portal.open_context(
                simple_rpc,  # taken from pytest parameterization
                data=10,

            ) as (ctx, sent),

            ctx.open_stream() as stream,
        ):

            assert sent == 11

            count: int = 0
            # receive msgs using async for style
            await stream.send('ping')

            msg: str
            async for msg in stream:
                assert msg == 'pong'
                await stream.send('ping')
                count += 1

                if count >= 9:
                    break

        # explicitly teardown the daemon-actor
        await portal.cancel_actor()


if __name__ == '__main__':
    trio.run(main)
