Skip to content

Instantly share code, notes, and snippets.

@bvanderveen
Created August 19, 2012 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bvanderveen/3390660 to your computer and use it in GitHub Desktop.
Save bvanderveen/3390660 to your computer and use it in GitHub Desktop.
// from RichB, https://groups.google.com/forum/#!msg/kayak-http/ivzlD8HoF9w/7reCjodx2-AJ%5B1-25%5D
class FileProducer : IDataProducer
{
// Members
private string m_fileName;
private FileStream m_fileStream;
private IDataConsumer m_consumer;
// Constructor
public FileProducer(string fileName)
{
// The stream that we'll serve up
m_fileStream = null;
// Check that the file that we are going to serve actually exists
if (File.Exists(fileName) == false)
{
throw new Exception("File does not exist");
}
else
{
m_fileName = fileName;
}
}
// Returns either a continuation or NULL if no continuation
public IDisposable Connect(IDataConsumer channel)
{
// Store a handle to the data consumer
m_consumer = channel;
// Open the file that we want to send
m_fileStream = File.OpenRead(m_fileName);
// Send data
Send();
// Return a handle to a disconnector
return new FileDisconnector(m_fileStream);
}
private void Send()
{
// Buffer to hold bytes read from file
byte[] buffer = new byte[1024];
// If the file is closed
if (m_fileStream.CanRead == false)
{
return;
}
// Set up an async callback to write data to the consumer
m_fileStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(x =>
{
// Wait for a read on the file to complete
int bytesRead = m_fileStream.EndRead(x);
// Will the consumer invoke continuation?
bool waitOnClient = m_consumer.OnData(new ArraySegment<byte>(buffer, 0, bytesRead), Send);
// If we've hit the end of the stream
if (m_fileStream.Position >= m_fileStream.Length)
{
m_fileStream.Close();
m_consumer.OnEnd();
return;
}
// If we aren't waiting on the client to request more data
else if (waitOnClient == false)
{
Send();
}
}), null);
}
}
class FileDisconnector : IDisposable
{
// Members
private FileStream m_fileStream;
// Constructor
public FileDisconnector(FileStream fileStream)
{
m_fileStream = fileStream;
}
public void Dispose()
{
m_fileStream.Close();
}
}
@bvanderveen
Copy link
Author

One way this could be improved is if the buffer was only allocated one, in the constructor say. Also, it could catch the exceptions thrown by BeginRead or EndRead and yield them via OnError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment