Files
32feet/InTheHand.Net.Bluetooth/Platforms/iOS/ExternalAccessoryNetworkStream.cs
2022-06-10 18:33:54 +01:00

146 lines
4.1 KiB
C#

// 32feet.NET - Personal Area Networking for .NET
//
// InTheHand.Net.Sockets.iOS.ExternalAccessoryNetworkStream (iOS)
//
// Copyright (c) 2018-2022 In The Hand Ltd, All rights reserved.
// This source code is licensed under the MIT License
using ExternalAccessory;
using Foundation;
using System;
using System.IO;
using System.Net.Sockets;
namespace InTheHand.Net.Sockets.iOS
{
internal class ExternalAccessoryNetworkStream : NonSocketNetworkStream
{
private NSInputStream _inputStream;
private NSOutputStream _outputStream;
private MemoryStream _outputBuffer = new MemoryStream();
private EAStreamDelegate _delegate;
private bool _streamReady = false;
internal ExternalAccessoryNetworkStream(EASession session)
{
_delegate = new EAStreamDelegate(this);
_inputStream = session.InputStream;
_outputStream = session.OutputStream;
_inputStream.Open();
_outputStream.Delegate = _delegate;
_outputStream.Schedule(NSRunLoop.Current,
#if NET6_0_OR_GREATER
NSRunLoopMode.Default
#else
NSRunLoop.NSDefaultRunLoopMode
#endif
);
_outputStream.Open();
}
internal class EAStreamDelegate : NSStreamDelegate
{
private ExternalAccessoryNetworkStream _stream;
internal EAStreamDelegate(ExternalAccessoryNetworkStream stream)
{
_stream = stream;
}
public override void HandleEvent(NSStream theStream, NSStreamEvent streamEvent)
{
if (theStream == _stream._outputStream && streamEvent == NSStreamEvent.HasSpaceAvailable)
{
_stream._streamReady = true;
_stream.Flush();
}
}
}
protected override void Dispose(bool disposing)
{
if(_inputStream is object)
{
_inputStream.Close();
_inputStream.Dispose();
_inputStream = null;
}
if(_outputStream is object)
{
_outputStream.Close();
_outputStream.Unschedule(NSRunLoop.Current,
#if NET6_0_OR_GREATER
NSRunLoopMode.Default
#else
NSRunLoop.NSDefaultRunLoopMode
#endif
);
_outputStream.Dispose();
_outputStream = null;
}
base.Dispose(disposing);
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => 0;
public override long Position { get => 0; set => throw new NotSupportedException(); }
public override void Flush()
{
if (_outputBuffer is object && _outputBuffer.Length > 0)
{
byte[] buffer = new byte[_outputBuffer.Length];
_outputBuffer.Read(buffer, 0, buffer.Length);
_outputBuffer.Dispose();
_outputBuffer = null;
_outputStream.Write(buffer);
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return (int)_inputStream.Read(buffer, offset, (nuint)count);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (_streamReady)
{
_outputStream.Write(buffer, offset, (nuint)count);
}
else
{
_outputBuffer.Write(buffer, offset, count);
}
}
public override bool DataAvailable
{
get
{
return _inputStream.HasBytesAvailable();
}
}
}
}