Add new sample - CustomInputStream

This commit is contained in:
Rolf Bjarne Kvinge 2012-05-04 12:51:47 +02:00
Родитель 3b1709b284
Коммит af478bf807
7 изменённых файлов: 459 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,92 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.Dialog;
namespace InputStreamTest
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
DialogViewController dvc;
NativeUploader uploader;
StyledStringElement status;
StyledStringElement upload;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
dvc = new DialogViewController (new RootElement ("InputStreamTest")
{
new Section () {
(upload = new StyledStringElement ("Upload", Upload)),
(status = new StyledStringElement ("")),
}
});
upload.Alignment = UITextAlignment.Center;
status.Alignment = UITextAlignment.Center;
window.RootViewController = dvc;
window.MakeKeyAndVisible ();
return true;
}
void Upload ()
{
TcpListener listener = new TcpListener (new IPEndPoint (IPAddress.Loopback, 0));
listener.Start ();
Console.WriteLine ("Listening on: {0}", listener.LocalEndpoint);
uploader = new NativeUploader ();
uploader.UploadStream ("http://127.0.0.1:" + ((IPEndPoint) listener.LocalEndpoint).Port.ToString (), 1000, () =>
{
Console.WriteLine ("Upload completed.");
});
listener.BeginAcceptSocket ((IAsyncResult res) =>
{
ThreadPool.QueueUserWorkItem ((v) =>
{
using (var socket = listener.EndAcceptSocket (res)) {
byte [] buffer = new byte[1024];
int read;
// receive headers
read = socket.Receive (buffer);
BeginInvokeOnMainThread (() => { status.Caption = "Received headers..."; dvc.ReloadData (); });
Console.WriteLine ("\n" + System.Text.ASCIIEncoding.ASCII.GetString (buffer, 0, read));
// send 100 Continue
socket.Send (System.Text.ASCIIEncoding.ASCII.GetBytes (@"HTTP/1.1 100 Continue\r\n\r\n"));
// receive data
read = socket.Receive (buffer);
BeginInvokeOnMainThread (() => { status.Caption = "Received data"; dvc.ReloadData (); });
Console.WriteLine ("\n" + System.Text.ASCIIEncoding.ASCII.GetString (buffer, 0, read));
// send 200 OK
socket.Send (System.Text.ASCIIEncoding.ASCII.GetBytes (@"HTTP/1.1 200 OK\r\n\r\n"));
}
listener.Stop ();
});
}, null);
}
static void Main (string[] args)
{
UIApplication.Main (args, null, "AppDelegate");
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}</ProjectGuid>
<ProjectTypeGuids>{6BC8ED88-2882-458C-8E55-DFD12B67127B};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>InputStreamTest</RootNamespace>
<AssemblyName>InputStreamTest</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchDebug>true</MtouchDebug>
<MtouchProfiling>true</MtouchProfiling>
<MtouchLink>None</MtouchLink>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Commandlineparameters>foobar</Commandlineparameters>
<CrashReportingApiKey />
<MtouchUseSGen>true</MtouchUseSGen>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<MtouchLink>None</MtouchLink>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchDebug>true</MtouchDebug>
<MtouchProfiling>true</MtouchProfiling>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MtouchExtraArgs>--keeptemp -v -v -v</MtouchExtraArgs>
<MtouchI18n />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<CodesignKey>iPhone Developer</CodesignKey>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<MtouchI18n />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="monotouch" />
<Reference Include="MonoTouch.Dialog-1" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppDelegate.cs" />
<Compile Include="NativeUploader.cs" />
<Compile Include="ZInputStream.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InputStreamTest", "InputStreamTest.csproj", "{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|iPhoneSimulator = Debug|iPhoneSimulator
Release|iPhoneSimulator = Release|iPhoneSimulator
Debug|iPhone = Debug|iPhone
Release|iPhone = Release|iPhone
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhone.ActiveCfg = Debug|iPhone
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhone.Build.0 = Debug|iPhone
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhone.ActiveCfg = Release|iPhone
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhone.Build.0 = Release|iPhone
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{30C54D9F-CAFA-4A7C-A6DA-14AE82D3093F}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = InputStreamTest.csproj
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using MonoTouch.Foundation;
namespace InputStreamTest
{
public class NativeUploader : NSObject
{
NSMutableUrlRequest request;
NSUrlConnection url_connection;
ZInputStream random_input_stream;
Dictionary<string,string> headers;
protected override void Dispose (bool disposing)
{
if (url_connection != null) {
url_connection.Dispose ();
url_connection = null;
}
if (request != null) {
request.BodyStream = null;
request.Dispose ();
request = null;
}
if (random_input_stream != null) {
random_input_stream.Dispose ();
random_input_stream = null;
}
base.Dispose (disposing);
}
public void AddHeader (string key, string value)
{
if (headers == null)
headers = new Dictionary<string, string> ();
headers.Add (key, value);
}
public void UploadStream (string url, long content_length, Action completed)
{
if (url == null)
throw new ArgumentNullException ("url");
AddHeader ("Expect", "100-continue");
AddHeader ("Content-Type", "application/octet-stream");
AddHeader ("Content-Length", content_length.ToString ());
InvokeOnMainThread (delegate {
try {
request = CreateNativePostRequest (url, content_length);
} catch (Exception e) {
Console.WriteLine ("Exception uploading stream");
Console.WriteLine (e);
completed ();
return;
}
url_connection = NSUrlConnection.FromRequest (request, new NativeUrlDelegate ((body) => {
completed ();
request.Dispose ();
}, (reason) => {
Console.WriteLine ("upload failed: " + reason);
completed ();
}));
});
}
NSMutableUrlRequest CreateNativePostRequest (string url, long content_length)
{
NSUrl nsurl = NSUrl.FromString (url);
if (nsurl == null)
throw new Exception ("Invalid upload URL, could not create NSUrl from: '" + url + "'.");
NSMutableUrlRequest request = new NSMutableUrlRequest (nsurl);
request.HttpMethod = "POST";
random_input_stream = new ZInputStream (content_length);
request.BodyStream = random_input_stream;
if (headers != null) {
foreach (var header in headers)
request [header.Key] = header.Value;
}
return request;
}
private class NativeUrlDelegate : NSUrlConnectionDelegate {
Action<string> success_callback;
Action<string> failure_callback;
NSMutableData data;
int status_code;
public NativeUrlDelegate (Action<string> success, Action<string> failure)
{
success_callback = success;
failure_callback = failure;
data = new NSMutableData();
}
public override void ReceivedData (NSUrlConnection connection, NSData d)
{
data.AppendData (d);
}
public override void ReceivedResponse (NSUrlConnection connection, NSUrlResponse response)
{
var http_response = response as NSHttpUrlResponse;
if (http_response == null) {
Console.WriteLine ("Received non HTTP url response: '{0}'", response);
status_code = -1;
return;
}
status_code = http_response.StatusCode;
Console.WriteLine ("Status code of result: '{0}'", status_code);
}
public override void FailedWithError (NSUrlConnection connection, NSError error)
{
if (failure_callback != null)
failure_callback (error.LocalizedDescription);
}
public override void FinishedLoading (NSUrlConnection connection)
{
if (status_code != 200) {
failure_callback (string.Format ("Did not receive a 200 HTTP status code, received '{0}'", status_code));
return;
}
success_callback (data.ToString ());
}
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
CustomInputStream
=================
This sample illustrates how to derive from NSInputStream and create subclass that is toll-free
bridged to CFReadStream that can be used with NSMutableUrlRequest.
Note that the API required to implement a subclass of NSInputStream that is toll-free bridged to
CFReadStream is considered private API by Apple, and may thus cause an app to be rejected
from the AppStore.
This sample requires at least MonoTouch 5.3.4.
Authors
-------
Rolf Bjarne Kvinge

Просмотреть файл

@ -0,0 +1,84 @@
using System;
using System.Runtime.InteropServices;
using MonoTouch.CoreFoundation;
using MonoTouch.Foundation;
namespace InputStreamTest
{
[Preserve (AllMembers = true)]
public class ZInputStream : NSInputStream
{
NSStreamStatus status;
long read_length;
long total_length;
public ZInputStream (long total_length) : base ()
{
status = NSStreamStatus.NotOpen;
this.total_length = total_length;
}
public override NSStreamStatus Status {
get {
return status;
}
}
public override void Open ()
{
status = NSStreamStatus.Open;
Notify (CFStreamEventType.OpenCompleted);
}
public override void Close ()
{
status = NSStreamStatus.Closed;
}
public override bool HasBytesAvailable ()
{
return total_length > read_length;
}
public override int Read (IntPtr buffer, uint len)
{
int actual = Math.Min ((int) len, (int) (total_length - read_length));
byte [] bytes = new byte [actual];
for (int i = 0; i < actual; i++)
bytes [i] = (byte) 'z';
read_length += actual;
Marshal.Copy (bytes, 0, buffer, actual);
if (actual == 0)
Notify (CFStreamEventType.EndEncountered);
return actual;
}
protected unsafe override bool GetBuffer (out IntPtr buffer, out uint len)
{
// Just call the base implemention (which will return false)
return base.GetBuffer (out buffer, out len);
}
protected override bool SetCFClientFlags (CFStreamEventType inFlags, IntPtr inCallback, IntPtr inContextPtr)
{
// Just call the base implementation, which knows how to handle everything.
return base.SetCFClientFlags (inFlags, inCallback, inContextPtr);
}
public override void ScheduleInCFRunLoop (IntPtr runloop, string mode)
{
Notify (CFStreamEventType.HasBytesAvailable);
}
public override void UnscheduleInCFRunLoop (IntPtr runloop, string mode)
{
// Nothing to do here
}
}
}