Skip to content

Instantly share code, notes, and snippets.

@atsushieno
Created September 22, 2009 18:14
Show Gist options
  • Save atsushieno/191293 to your computer and use it in GitHub Desktop.
Save atsushieno/191293 to your computer and use it in GitHub Desktop.
C# lingr(2) client
// It uses limited set of WCF features that does not such that much.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Json;
using System.Net;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
/*
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
*/
using System.Text;
using System.Xml;
namespace Slingr
{
public class Test
{
}
public class LingrRoom
{
public LingrRoom (string room, string session, int counter)
{
this.Room = room;
this.Session = session;
this.Counter = counter;
}
public string Room { get; set; }
public string Session { get; set; }
public int Counter { get; set; }
}
static class DictionaryExtension
{
public static JsonValue Get (this JsonObject dic, string key)
{
JsonValue value;
return dic.TryGetValue (key, out value) ? value : null;
}
}
public abstract class UnWCFLingrClientBase
{
public static TextWriter DebugWriter = TextWriter.Null;//Console.Out;
protected UnWCFLingrClientBase (Uri baseUri)
{
this.base_address = baseUri;
}
Dictionary<string,string> ToParameters (params string [] pairs)
{
var pl = new Dictionary<string,string> (StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i < pairs.Length; i += 2)
pl [pairs [i]] = pairs [i + 1];
return pl;
}
DataContractJsonSerializer sess_stat_ser = new DataContractJsonSerializer (typeof (SessionStatusResponse));
protected SessionStatusResponse ToSessionStatusResponse (byte [] raw)
{
return (SessionStatusResponse) sess_stat_ser.ReadObject (JsonReaderWriterFactory.CreateJsonReader (raw, new XmlDictionaryReaderQuotas ()));
}
Uri base_address;
protected byte [] RequestData (string template, params string [] parameters)
{
var ut = new UriTemplate (template, true);
var pl = ToParameters (parameters);
var uri = ut.BindByName (base_address, pl, false);
DebugWriter.WriteLine ("URI: " + uri);
var wc = new WebClient ();
return wc.DownloadData (uri);
}
protected JsonObject Request (string template, params string [] parameters)
{
string s = Encoding.UTF8.GetString (RequestData (template, parameters));
DebugWriter.WriteLine (s);
return JsonValue.Parse (s) as JsonObject;
}
}
public class UnWCFLingrEventClient : UnWCFLingrClientBase, ILingrEventContract
{
public UnWCFLingrEventClient ()
: base (new Uri ("http://lingr.com:8080"))
{
}
#region ILingrEventContract implementation
DataContractJsonSerializer obs_ser = new DataContractJsonSerializer (typeof (ObserveResponse));
public ObserveResponse Observe (string session, int counter)
{
var raw = RequestData ("api/event/observe?session={session}&counter={counter}", "session", session, "counter", counter.ToString ());
// It is complicated: since .NET deserializer expects
// CLR type information ("__type":"RoomPresence:#Slingr")
// but the server is *not* WCF, it must be added manually.
// What a silly design problem.
var js = (JsonObject) JsonValue.Parse (Encoding.UTF8.GetString (raw));
var newevts = new JsonArray ();
if (js ["status"] as string == "ok") {
foreach (JsonObject ev in (JsonArray) js ["events"]) {
if (ev.ContainsKey ("message"))
newevts.Add (new JsonObject(AddTypeInfo ("RoomMessage:#Slingr", ev)));
else
newevts.Add (new JsonObject(AddTypeInfo ("RoomPresence:#Slingr", ev)));
}
js ["events"] = newevts;
raw = Encoding.UTF8.GetBytes (js.ToString ());
}
return (ObserveResponse) obs_ser.ReadObject (JsonReaderWriterFactory.CreateJsonReader (raw, new XmlDictionaryReaderQuotas ()));
}
IEnumerable<KeyValuePair<string,JsonValue>> AddTypeInfo (string type, JsonObject obj)
{
yield return new KeyValuePair<String,JsonValue> ("__type", type);
foreach (var item in obj)
yield return item;
}
#endregion
}
public class UnWCFLingrCilent : UnWCFLingrClientBase, ILingrContract
{
public UnWCFLingrCilent ()
: base (new Uri ("http://lingr.com"))
{
}
void FillStatus (LingrResponse r, JsonObject j)
{
r.Status = (string) j.Get ("status");
r.ErrorCode = (string) j.Get ("code");
r.ErrorDetail = (string) j.Get ("detail");
}
#region ILingrContract implementation
public SessionStatusResponse CreateAnonymousSession ()
{
var raw = RequestData ("api/session/create");
return ToSessionStatusResponse (raw);
}
public SessionStatusResponse CreateSession (string user, string password)
{
var raw = RequestData ("api/session/create?user={user}&password={password}", "user", user, "password", password);
return ToSessionStatusResponse (raw);
}
public SessionStatusResponse SetPresence (string session, string nickname, string presence)
{
var raw = RequestData ("api/session/set_presence?session={session}&nickname={nickname}&presence={presence}", "session", session, "nickname", nickname, "presence", presence);
return ToSessionStatusResponse (raw);
}
public SessionStatusResponse VerifySession (string session)
{
var raw = RequestData ("api/session/verify?session={session}", "session", session);
return ToSessionStatusResponse (raw);
}
EmptyResponse ToEmptyResponse (JsonObject js)
{
var ret = new EmptyResponse ();
FillStatus (ret, js);
return ret;
}
public EmptyResponse DestroySession (string session)
{
var js = Request ("api/session/destroy?session={session}", "session", session);
return ToEmptyResponse (js);
}
IEnumerable<string> AsStringEnumerable (JsonArray a)
{
foreach (JsonPrimitive item in a)
yield return item;
}
public RoomsResponse GetRooms (string session)
{
var js = Request ("api/user/get_rooms?session={session}", "session", session);
var ret = new RoomsResponse ();
FillStatus (ret, js);
if (ret.Status == "ok") {
var e = AsStringEnumerable ((JsonArray) js.Get ("rooms"));
ret.Rooms = e.ToArray ();
}
return ret;
}
DataContractJsonSerializer say_res_ser = new DataContractJsonSerializer (typeof (SayResponse));
public SayResponse Say (string session, string room, string nickname, string text, string localId)
{
var raw = RequestData ("api/room/say?session={session}&room={room}&nickname={nickname}&text={text}&local_id={local_id}", "session", session, "room", room, "nickname", nickname, "text", text, "local_id", localId);
return (SayResponse) say_res_ser.ReadObject (JsonReaderWriterFactory.CreateJsonReader (raw, new XmlDictionaryReaderQuotas ()));
}
DataContractJsonSerializer show_res_ser = new DataContractJsonSerializer (typeof (ShowResponse));
public ShowResponse Show (string session, string room)
{
var raw = RequestData ("api/room/show?session={session}&room={room}", "session", session, "room", room);
return (ShowResponse) show_res_ser.ReadObject (JsonReaderWriterFactory.CreateJsonReader (raw, new XmlDictionaryReaderQuotas ()));
}
DataContractJsonSerializer sub_stat_ser = new DataContractJsonSerializer (typeof (SubscriptionStatusResponse));
SubscriptionStatusResponse ToSubscriptionStatus (byte [] raw)
{
return (SubscriptionStatusResponse) sub_stat_ser.ReadObject (JsonReaderWriterFactory.CreateJsonReader (raw, new XmlDictionaryReaderQuotas ()));
}
public SubscriptionStatusResponse Subscribe (string session, string room)
{
var raw = RequestData ("api/room/subscribe?session={session}&room={room}", "session", session, "room", room);
return ToSubscriptionStatus (raw);
}
public EmptyResponse Unsubscribe (string session, string room)
{
var js = Request ("api/room/unsubscribe?session={session}&room={room}", "session", session, "room", room);
return ToEmptyResponse (js);
}
#endregion
}
public class LingrClient : IDisposable
{
ILingrContract lingr;
ILingrEventContract lingr_event;
public LingrClient ()
{
/*
var cf = new WebChannelFactory<ILingrClient> (
new CustomBinding (
new WebMessageEncodingBindingElement (),
new HttpTransportBindingElement () { ManualAddressing = true }),
new Uri ("http://lingr.com"));
cf.Endpoint.Behaviors.Add (new LingrEndpointBehavior ());
lingr = cf.CreateChannel ();
*/
lingr = new UnWCFLingrCilent ();
lingr_event = new UnWCFLingrEventClient ();
Rooms = new List<LingrRoom> ();
}
public string Presence { get; private set; }
public string Session { get; private set; }
public string NickName { get; private set; }
public string PublicId { get; private set; }
public IList<LingrRoom> Rooms { get; private set; }
public void Dispose ()
{
if (lingr == null)
return;
if (Session != null)
DestroySession ();
lingr = null;
}
void CheckErrorResponse (LingrResponse res)
{
if (res.Status != "ok")
throw new LingrException (res);
}
void SetSessionStatus (SessionStatusResponse res)
{
CheckErrorResponse (res);
Session = res.Session;
Presence = res.Presence;
PublicId = res.PublicId;
NickName = res.NickName;
}
void CheckSessionExistence ()
{
if (Session == null)
throw new InvalidOperationException ("No session is established");
}
// Session API wrappers
public void CreateAnonymousSession (string nick)
{
var res = lingr.CreateAnonymousSession ();
SetSessionStatus (res);
this.NickName = nick;
}
public void CreateSession (string user, string password)
{
var res = lingr.CreateSession (user, password);
SetSessionStatus (res);
}
public void DestroySession ()
{
CheckSessionExistence ();
var res = lingr.DestroySession (Session);
CheckErrorResponse (res);
Session = null;
Presence = null;
}
public void VerifySession ()
{
CheckSessionExistence ();
var res = lingr.VerifySession (Session);
SetSessionStatus (res);
}
public void SetPresence (bool online)
{
CheckSessionExistence ();
var res = lingr.SetPresence (Ses
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment