Jump to content

New .NET Library for Web UI


tombull

Recommended Posts

Hi, I've created a new .NET wrapper library for the uTorrent Web UI.

You can get it at: http://www.codeplex.com/uTorrentClient

It uses .NET Framework 3.5 SP1 and the new WCF bindings that allow WCF to communicate with REST services in JSON. The uTorrent Web UI API is a REST service that returns JSON, so this seemed like a sensible idea.

It is a complete implementation of all the functionality of the uTorrent Web UI API, using a reasonably nice object-oriented structure, and has a fair amount of comments for documentation.

I've not tested it very well yet, because I've not yet written an application to test it. If anyone else tests it or writes an application using it, you can add issues on the CodePlex site, and I will fix them when I have time.

EDIT 2008-12-11:

I've updated the wrapper library to include some bug fixes and extra features which should support writing good user interfaces using the library. I've also added a basic test application called the 'Fat Controller' which is a UI that looks a bit like uTorrent, written in C# using the library.

Link to comment
Share on other sites

  • 9 months later...
  • 2 weeks later...
  • 1 month later...
  • 2 months later...
  • 2 months later...

@descention: Thanks for updating the library!

Now the login works fine but for some reason I get "The remote server returned an unexpected response: (300) ERROR." when trying to fetch torrent files or when using any of the torrent methods, e.g. pause and stop.

Anyone got it working?

Link to comment
Share on other sites

My best bet is that the token was inserted incorrectly into the URL.

Judging by the service definition, it's inserting the token at the end of the request, which won't always work -- as mentioned here. The token shouldnt come anywhere after the first position after list or action, but it clearly does in the service definitions in descention's code.

Link to comment
Share on other sites

Cool :)

I don't know, but if only for the sake of code alignment/consistency/prettiness and all that jazz, I would probably put the token as the first parameter. The token isn't something you want to consciously think about, so leaving it out of the way at the beginning (rather than in between an action and its parameters/arguments) flows more nicely... to me. It looks more consistent when you're scanning through the various requests too.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.IO;

namespace Cleverscape.UTorrentClient.WebClient.ServiceDefinition
{
[ServiceContract]
public interface IUTorrentWebClient
{
[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&list=1"
)]
TorrentsAndLabels GetAllTorrentsAndLabels(string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&list=1&cid={CacheID}"
)]
UpdatedTorrentsAndLabels GetUpdatedTorrentsAndLabels(string CacheID, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=getsettings"
)]
UTorrentSettings GetSettings(string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setsetting&s={SettingName}&v={SettingValue}"
)]
GenericResponse SetStringSetting(string SettingName, string SettingValue, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setsetting&s={SettingName}&v={SettingValue}"
)]
GenericResponse SetBooleanSetting(string SettingName, string SettingValue, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setsetting&s={SettingName}&v={SettingValue}"
)]
GenericResponse SetIntegerSetting(string SettingName, int SettingValue, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=getfiles&hash={TorrentHash}"
)]
TorrentFiles GetFiles(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=getprops&hash={TorrentHash}"
)]
TorrentProperties GetProperties(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setprops&hash={TorrentHash}&s={PropertyName}&v={PropertyValue}"
)]
GenericResponse SetStringProperty(string TorrentHash, string PropertyName, string PropertyValue, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setprops&hash={TorrentHash}&s={PropertyName}&v={PropertyValue}"
)]
GenericResponse SetIntegerProperty(string TorrentHash, string PropertyName, int PropertyValue, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setprops&hash={TorrentHash}&s={PropertyName}&v={PropertyValue}"
)]
GenericResponse SetLongProperty(string TorrentHash, string PropertyName, long PropertyValue, string token);


[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=start&hash={TorrentHash}"
)]
GenericResponse StartTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=stop&hash={TorrentHash}"
)]
GenericResponse StopTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=pause&hash={TorrentHash}"
)]
GenericResponse PauseTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=forcestart&hash={TorrentHash}"
)]
GenericResponse ForceStartTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=unpause&hash={TorrentHash}"
)]
GenericResponse UnPauseTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=recheck&hash={TorrentHash}"
)]
GenericResponse RecheckTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=remove&hash={TorrentHash}"
)]
GenericResponse RemoveTorrent(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=removedata&hash={TorrentHash}"
)]
GenericResponse RemoveTorrentAndData(string TorrentHash, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=setprio&hash={TorrentHash}&p={Priority}&f={FileNumber}"
)]
GenericResponse SetFilePriority(string TorrentHash, int FileNumber, int Priority, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/?token={token}&action=add-url&s={TorrentUrl}"
)]
GenericResponse AddTorrentFromUrl(string TorrentUrl, string token);

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "/token.html"
)]
Stream getToken();

}

}

Completely untested. But I seriously doubt moving the token would really break it either :P

Aside: I think it would probably be even cleaner to have one internal call that inserts the actual token, through which all other requests actually route their GET parameters -- that way, only one function has to deal with tokens, and all the others don't need the knowledge. But that's probably somewhat more involved a change, so oh well.
Link to comment
Share on other sites

  • 3 weeks later...
  • 1 month later...

Well first of C# is kinda new to me. The last time I used the C language was playing with good old C for dos... :P

A Friend of mine have tried to get me to try C# for a while and now I have the perfect opportunity to try it...

I'm making an all in one server download manager for HTTP, FTP and Torrents in Microsoft Visual C# 2010..

I have updated the library to .Net 4.0 and added the library to my project.

But I'm kinda lost right now. How do I use this Library? I guess I need to feed it some server settings..

But how and then what?

An example using this would be helpful.. Couldn't find the source for The Fat Controller...

Any help would be appreciated... :)

Link to comment
Share on other sites

try this link to download the source:

http://utorrentclient.codeplex.com/SourceControl/changeset/changes/28201#

On an unrelated issue: Could someone be able to advise me on where I can increase the 'maxReceivedMessageSize' property. It's set to the default size of 65535 and I keep getting an exception error from VS2010 when I try and load the files from a large torrent. The only information I can find is this bit of code for a configuration file:

<configuration>

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="Binding1"

maxReceivedMessageSize = "1000000">

<security mode="None" />

</binding>

</basicHttpBinding>

</bindings>

</system.serviceModel>

</configuration>

I've tried inserting 'uTorrentCustomBinding' in place of 'Binding1' but I can't seem to find the right config file to put this in, or if it is even relevant.

Thank You.

Link to comment
Share on other sites

  • 3 weeks later...

nobody can help me ???

hi i have a probleme with the app fat controller from tombull, when i remove a torrent from utorrent , the app crash

can someone help me

exeption here

Code :

Code:

L'exception System.Reflection.TargetInvocationException n'a pas été gérée

Message="Une exception a été levée par la cible d'un appel."

Source="mscorlib"

StackTrace:

à System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)

à System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)

à System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)

à System.Delegate.DynamicInvokeImpl(Object[] args)

à System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)

à System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

à System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

à System.Windows.Threading.DispatcherOperation.InvokeImpl()

à System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)

à System.Threading.ExecutionContext.runTryCode(Object userData)

à System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)

à System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

à System.Windows.Threading.DispatcherOperation.Invoke()

à System.Windows.Threading.Dispatcher.ProcessQueue()

à System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

à MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)

à MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)

à System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)

à System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

à System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)

à System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)

à System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)

à MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)

à MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)

à System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)

à System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)

à System.Windows.Threading.Dispatcher.Run()

à System.Windows.Application.RunDispatcher(Object ignore)

à System.Windows.Application.RunInternal(Window window)

à System.Windows.Application.Run(Window window)

à System.Windows.Application.Run()

à WpfApplication2.App.Main() dans C:\Users\Vinzzz\Documents\Visual Studio 2008\Projects\WpfApplication2\WpfApplication2\App.cs:ligne 119

à System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

à System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

à Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()

à System.Threading.ThreadHelper.ThreadStart_Context(Object state)

à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

à System.Threading.ThreadHelper.ThreadStart()

InnerException: System.InvalidOperationException

Message="L'événement CollectionRemove doit spécifier la position de l'élément."

Source="PresentationFramework"

StackTrace:

à MS.Internal.Data.EnumerableCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)

à System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)

à Cleverscape.UTorrentClient.WebClient.TorrentCollection.CallCollectionChangedAsync(NotifyCollectionChangedEventArgs EventArgs)

InnerException:

Link to comment
Share on other sites

  • 3 weeks later...

Well I figured it out. I had to add the 'maxreceivedmessagesize' property to HttpTransportBindingElement:

CustomBinding uTorrentCustomBinding = new CustomBinding(

new WebMessageEncodingBindingElement() { ContentTypeMapper = new JsonContentTypeMapper() },

new HttpTransportBindingElement() { MaxReceivedMessageSize = 1000000, ManualAddressing = true, AuthenticationScheme = System.Net.AuthenticationSchemes.Basic, Realm = "uTorrent", AllowCookies = false }

);

And then build the dll again.

Link to comment
Share on other sites

  • 1 month later...

Hi,

I've been trying to add files and streams using the AddTorrent function but I always get "The remote server returned an error: (400) Bad Request.".

Perhaps you then respond with, why don't you use the AddTorrentFromUrl, well that's because some of the places I pick torrents from are really slow to fetch from and mostly they fail when adding to WebUI. But downloading the file isn't a problem from C#, it just takes time.

So I've tried modifying the code and use different codes for multipart sending, 2 or 3 different from this page -> http://stackoverflow.com/questions/219827/multipart-forms-from-c-client <- but without success. I always get the same error.

When I use the WebUI itself to upload files it works fine.

So any suggestions?

EDIT:

I created my own webpage that received the torrent and it worked fine. So it seems that the uTorrent webserver seems to be the problem. Any comments regarding that?

Link to comment
Share on other sites

  • 2 weeks later...

Hello Prottan,

Just wanted to give my thanks to you for updating this API library. It's sad to see this isn't officially supported / updated by the uTorrent devs.

I've been using this library in my program for some time but when I updated to the new beta it stopped working. I tried out your update / fix and everything was working great again. That is until I just updated to version 2.2. Everything stopped working and now I'm receiving the (400) error again. I investigated and it seems to be throwing the error up in the GetTorrentsAndLabelsFresh() function which leads me to believe it's a possible problem with the token? Your knowledge on this would be better than mine.

Any ideas as to what I need to change to get it to work again or, do you possibly plan on releasing another update in the new future?

Thanks again for all the work you've done in getting this library to work again.

Link to comment
Share on other sites

Nothing wrong with a project being community-maintained. Community projects are generally encouraged, hence the documentation provided on the backend API in the first place.

I never meant to imply that I was against community-maintained projects. Sorry if it came across like that. I just meant it would easier, as 3rd party developer, if the .Net API library was maintained officially especially when changes are made to the backend that can affect the usability of the component.

This just happens to be a good example where it took two years for the library to be updated and as of version 2.2 it's no longer working again. With an officially supported library, this would solve the hassle of waiting for someone to update or having to delve into unfamiliar code to find a fix.

Link to comment
Share on other sites

@Sranshaft

I'm not running beta myself so I don't have this problem. I'm not planning to update to beta either since I like stable versions :)

When 2.2 gets proper and the API isn't working I'll probably try fixing it since I have an application using it.

But I'm afraid that I'm not planning to do any updates in the API until then.

I've just modified the code for my own use so it would work again, with the help of Ultima of course :D

And since people seems to be using the API and nobody was updating it I thought I should be a nice guy and give the changes to you (the community).

So either you run the stable version or try fixing the problem yourself :)

If you fix the problem it would be nice to give it back to the community since it's no longer seems to be maintained by the creator.

Thanks!

Link to comment
Share on other sites

Just a bit of update for those interested. It appears the problem occurs when the 'Enable Guest account with username:' feature is enabled, the library does not return a token thus returning the Error 400 code. When that option is disabled, things work accordingly with 2.2 beta and WebUI API.

Link to comment
Share on other sites

Eh? So the library is sending nothing for the token GET parameter while that option is enabled? When you say that the problem occurs when that option "is enabled", are you actually attempting to connect using the guest login when it fails? If so, what happens if you use the fully privileged login?

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...