Я пишу сервер, и одно из требований заключается в том, что он должен иметь возможность передавать данные клиентам без прямого запроса данных клиентом. Я использую каналы, но мне кажется, что это выходит за рамки возможностей каналов. Проблема, с которой я сталкиваюсь, заключается в том, что, похоже, нет способа определить, есть ли в сокете доступные данные или нет, и await заблокирует выполнение до тех пор, пока данные не будут доступны. Скажем, у меня есть следующие функции
getPacket :: Conduit ByteString IO ClientPacket --take a bytestring and yield a ClientPacket i.e. the ByteString deserialized into a sensible form
processPacket :: Conduit ClientPacket IO ServerPacket --take a ClientPacket and yield a ServerPacket i.e. a response to the client's request
putPacket :: Conduit ServerPacket IO ByteString --serialize the ServerPacket
затем соединяю кондуиты вместе с источником и стоком из библиотеки Conduit.Network
appSource appData $$ getPacket =$= processPacket =$= putPacket $= appSink appData
Теперь я ввожу источник данных извне канала и хочу включить эти данные в канал. Например, если бы это был чат-сервер, внешними данными были бы сообщения, отправленные другими клиентами. Проблема в том, что независимо от того, где я пытаюсь ввести эти внешние данные, они будут заблокированы вызовами ожидания. По сути, я закончу код, который выглядит так.
yield processOutsideData --deal with the outside data
data <- await --await data from upstream
Единственный способ, которым будет обработано больше внешних данных, — это если вышестоящий компонент что-то выдает, но вышестоящий компонент выдаст, только если он получит данные от клиента, чего я пытаюсь избежать. Я пытался использовать несколько потоков и TChan, чтобы решить эту проблему, но похоже, что appSource и appSink должны использоваться в одном потоке, иначе я получаю недопустимые исключения файловых дескрипторов из recv (что имеет смысл).
Однако, если источник сокета и приемник работают в одном и том же потоке, я снова сталкиваюсь с проблемой блокировки ожидания, и у меня нет возможности проверить, доступны ли данные из сокета. В этот момент кажется, что я ударился о стену с трубопроводами.
Но мне действительно нравится использовать кондуиты, и я бы предпочел продолжать их использовать. Итак, мои вопросы: есть ли способ сделать то, что я пытаюсь достичь с помощью каналов?