#region License /* * WebSocketService.cs * * The MIT License * * Copyright (c) 2012-2013 sta.blockhead * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #endregion using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Threading; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; namespace WebSocketSharp.Server { /// /// Provides the basic functions of the WebSocket service. /// /// /// The WebSocketService class is an abstract class. /// public abstract class WebSocketService { #region Private Fields private WebSocketContext _context; private WebSocketServiceManager _sessions; private WebSocket _websocket; #endregion #region Public Constructors /// /// Initializes a new instance of the class. /// public WebSocketService() { ID = String.Empty; IsBound = false; } #endregion #region Protected Properties /// /// Gets or sets the logging functions. /// /// /// If you wanted to change the current logger to the service own logger, you would set this property /// to a new instance that you created. /// /// /// A that provides the logging functions. /// protected Logger Log { get { return IsBound ? _websocket.Log : null; } set { if (!IsBound) return; _websocket.Log = value; } } /// /// Gets the collection of query string variables used in the WebSocket opening handshake. /// /// /// A that contains the collection of query string variables. /// protected NameValueCollection QueryString { get { return IsBound ? _context.QueryString : null; } } /// /// Gets the sessions to the . /// /// /// A that contains the sessions to the the . /// protected WebSocketServiceManager Sessions { get { return IsBound ? _sessions : null; } } #endregion #region Public Properties /// /// Gets the ID of the instance. /// /// /// A that contains an ID. /// public string ID { get; private set; } /// /// Gets a value indicating whether the instance is bound to a . /// /// /// true if the instance is bound to a ; otherwise, false. /// public bool IsBound { get; private set; } #endregion #region Private Methods private void onClose(object sender, CloseEventArgs e) { _sessions.Remove(ID); OnClose(e); } private void onError(object sender, ErrorEventArgs e) { OnError(e); } private void onMessage(object sender, MessageEventArgs e) { OnMessage(e); } private void onOpen(object sender, EventArgs e) { ID = _sessions.Add(this); OnOpen(); } #endregion #region Internal Methods internal void Bind(WebSocketContext context, WebSocketServiceManager sessions) { if (IsBound) return; if (!ProcessCookies(context.CookieCollection, context.WebSocket.CookieCollection)) { context.WebSocket.Close(HttpStatusCode.BadRequest); return; } _context = context; _sessions = sessions; _websocket = context.WebSocket; _websocket.OnOpen += onOpen; _websocket.OnMessage += onMessage; _websocket.OnError += onError; _websocket.OnClose += onClose; IsBound = true; } internal void SendAsync(byte[] data, Action completed) { _websocket.SendAsync(data, completed); } internal void SendAsync(string data, Action completed) { _websocket.SendAsync(data, completed); } #endregion #region Protected Methods /// /// Occurs when the inner receives a Close frame or the Stop method is called. /// /// /// A that contains the event data associated with a event. /// protected virtual void OnClose(CloseEventArgs e) { } /// /// Occurs when the inner gets an error. /// /// /// An that contains the event data associated with a event. /// protected virtual void OnError(ErrorEventArgs e) { } /// /// Occurs when the inner receives a data frame. /// /// /// A that contains the event data associated with a event. /// protected virtual void OnMessage(MessageEventArgs e) { } /// /// Occurs when the WebSocket connection has been established. /// protected virtual void OnOpen() { } /// /// Processes the cookies used in the WebSocket opening handshake. /// /// /// true if processing the cookies is successfully; otherwise, false. /// /// /// A that contains a collection of the HTTP Cookies received from the client. /// /// /// A that contains a collection of the HTTP Cookies to send to the client. /// protected virtual bool ProcessCookies(CookieCollection request, CookieCollection response) { return true; } #endregion #region Public Methods /// /// Broadcasts the specified array of to the clients of every instances /// in the . /// /// /// An array of to broadcast. /// public void Broadcast(byte[] data) { if (IsBound) _sessions.Broadcast(data); } /// /// Broadcasts the specified to the clients of every instances /// in the . /// /// /// A to broadcast. /// public void Broadcast(string data) { if (IsBound) _sessions.Broadcast(data); } /// /// Pings to the clients of every instances /// in the . /// /// /// A Dictionary<string, bool> that contains the collection of IDs and values /// indicating whether each instances received a Pong in a time. /// public Dictionary Broadping() { return Broadping(String.Empty); } /// /// Pings with the specified to the clients of every instances /// in the . /// /// /// A Dictionary<string, bool> that contains the collection of IDs and values /// indicating whether each instances received a Pong in a time. /// /// /// A that contains a message. /// public Dictionary Broadping(string message) { return IsBound ? _sessions.Broadping(message) : null; } /// /// Pings to the client of the instance. /// /// /// true if the instance receives a Pong in a time; otherwise, false. /// public bool Ping() { return Ping(String.Empty); } /// /// Pings with the specified to the client of the instance. /// /// /// true if the instance receives a Pong in a time; otherwise, false. /// /// /// A that contains a message. /// public bool Ping(string message) { return IsBound ? _websocket.Ping(message) : false; } /// /// Pings to the client of the instance /// associated with the specified . /// /// /// true if the instance receives a Pong in a time; otherwise, false. /// /// /// A that contains an ID that represents the destination for the Ping. /// public bool PingTo(string id) { return PingTo(id, String.Empty); } /// /// Pings with the specified to the client of the instance /// associated with the specified . /// /// /// true if the instance receives a Pong in a time; otherwise, false. /// /// /// A that contains an ID that represents the destination for the Ping. /// /// /// A that contains a message. /// public bool PingTo(string id, string message) { if (!IsBound) return false; WebSocketService service; return _sessions.TryGetWebSocketService(id, out service) ? service.Ping(message) : false; } /// /// Sends a binary data to the client of the instance. /// /// /// An array of that contains a binary data to send. /// public void Send(byte[] data) { if (IsBound) _websocket.Send(data); } /// /// Sends a text data to the client of the instance. /// /// /// A that contains a text data to send. /// public void Send(string data) { if (IsBound) _websocket.Send(data); } /// /// Sends a binary data to the client of the instance /// associated with the specified . /// /// /// A that contains an ID that represents the destination for the data. /// /// /// An array of that contains a binary data to send. /// public void SendTo(string id, byte[] data) { if (!IsBound) return; WebSocketService service; if (_sessions.TryGetWebSocketService(id, out service)) service.Send(data); } /// /// Sends a text data to the client of the instance /// associated with the specified . /// /// /// A that contains an ID that represents the destination for the data. /// /// /// A that contains a text data to send. /// public void SendTo(string id, string data) { if (!IsBound) return; WebSocketService service; if (_sessions.TryGetWebSocketService(id, out service)) service.Send(data); } /// /// Starts the instance. /// public void Start() { if (IsBound) _websocket.Connect(); } /// /// Stops the instance. /// public void Stop() { if (!IsBound) return; _websocket.Close(); } /// /// Stops the instance with the specified and . /// /// /// A that contains a status code indicating the reason for stop. /// /// /// A that contains a reason for stop. /// public void Stop(ushort code, string reason) { if (!IsBound) return; _websocket.Close(code, reason); } /// /// Stops the instance with the specified and . /// /// /// One of the values that contains a status code indicating the reason for stop. /// /// /// A that contains a reason for stop. /// public void Stop(CloseStatusCode code, string reason) { Stop((ushort)code, reason); } #endregion } }