Created
August 19, 2012 01:03
-
-
Save bvanderveen/3390660 to your computer and use it in GitHub Desktop.
Serving files in Kayak, contributed by RichB at https://groups.google.com/forum/#!msg/kayak-http/ivzlD8HoF9w/7reCjodx2-AJ%5B1-25%5D
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.