ServerOutput.vala 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. namespace Astralis {
  4. internal class ServerOutput : Object, AsyncOutput {
  5. const int MAX_CHUNKS = 5;
  6. private BinaryData current_chunk = null;
  7. private Series<ByteBuffer> chunks = new Series<ByteBuffer>();
  8. internal signal void on_new_chunk();
  9. internal signal void on_chunk_poped();
  10. private delegate void Handler();
  11. private bool _connected = true;
  12. public bool connected { get { return _connected; } }
  13. public bool write_would_block {
  14. get {
  15. return chunks.length > MAX_CHUNKS;
  16. }
  17. }
  18. internal void close_connection() {
  19. _connected = false;
  20. }
  21. public async void write (Invercargill.BinaryData data) throws Error {
  22. if (!_connected) {
  23. throw new IOError.CLOSED("Cannot write to disconnected client");
  24. }
  25. while(chunks.length > MAX_CHUNKS) {
  26. ulong handler_id = 0;
  27. handler_id = on_chunk_poped.connect(() => {
  28. SignalHandler.disconnect(this, handler_id);
  29. Idle.add(write.callback);
  30. });
  31. yield;
  32. }
  33. var buffer = data.to_byte_buffer();
  34. if(buffer.length > 0) {
  35. chunks.add(buffer);
  36. on_new_chunk();
  37. }
  38. }
  39. internal size_t read_chunk(void* buffer, size_t max_size) {
  40. if(current_chunk != null && current_chunk.peek_count() == 0) {
  41. current_chunk = null;
  42. }
  43. if(current_chunk == null && chunks.length == 0) {
  44. return 0;
  45. }
  46. if(current_chunk == null) {
  47. current_chunk = chunks.pop_start ();
  48. on_chunk_poped();
  49. }
  50. var size = current_chunk.write_to (buffer, max_size);
  51. current_chunk = current_chunk.skip((uint)size);
  52. return size;
  53. }
  54. }
  55. }