#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.Text; using System.Threading; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; namespace WebSocketSharp.Server { /// /// Provides the basic functions of the WebSocket service used by the WebSocket service host. /// /// /// The WebSocketService class is an abstract class. /// public abstract class WebSocketService : IWebSocketSession { #region Private Fields private WebSocket _websocket; private WebSocketContext _context; private WebSocketSessionManager _sessions; private DateTime _start; #endregion #region Public Constructors /// /// Initializes a new instance of the class. /// public WebSocketService () { IsBound = false; _start = DateTime.MaxValue; } #endregion #region Protected Properties /// /// Gets or sets the logging functions. /// /// /// If you want to change the current logger to the service own logger, you 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) _websocket.Log = value; } } /// /// Gets the manager of the sessions to the WebSocket service. /// /// /// A that manages the sessions to the WebSocket service. /// protected WebSocketSessionManager Sessions { get { return _sessions; } } #endregion #region Public Properties /// /// Gets the WebSocket connection request information. /// /// /// A that contains the WebSocket connection request information. /// public WebSocketContext Context { get { return _context; } } /// /// Gets the unique ID of the current instance. /// /// /// A that contains the unique ID. /// public string ID { get; private set; } /// /// Gets a value indicating whether the current instance /// has been bound to a . /// /// /// true if the current instance has been bound to /// a ; otherwise, false. /// public bool IsBound { get; private set; } /// /// Gets the time that the current instance has been started. /// /// /// A that represents the time that the current /// instance has been started. /// public DateTime StartTime { get { return _start; } } /// /// Gets the state of the WebSocket connection. /// /// /// One of the values. /// public WebSocketState State { get { return IsBound ? _websocket.ReadyState : WebSocketState.CONNECTING; } } #endregion #region Private Methods private void onClose (object sender, CloseEventArgs e) { if (ID == null) return; _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); if (ID == null) { _websocket.Close (CloseStatusCode.AWAY); return; } _start = DateTime.Now; OnOpen (); } #endregion #region Internal Methods internal void Bind (WebSocketContext context, WebSocketSessionManager sessions) { if (IsBound) return; _context = context; _sessions = sessions; _websocket = context.WebSocket; _websocket.CookiesValidation = ValidateCookies; _websocket.OnOpen += onOpen; _websocket.OnMessage += onMessage; _websocket.OnError += onError; _websocket.OnClose += onClose; IsBound = true; } #endregion #region Protected Methods /// /// Calls the method with the specified . /// /// /// A that contains an error message. /// protected virtual void Error (string message) { if (!message.IsNullOrEmpty ()) OnError (new ErrorEventArgs (message)); } /// /// Is called when the WebSocket connection has been closed. /// /// /// A that contains an event data associated with /// an inner event. /// protected virtual void OnClose (CloseEventArgs e) { } /// /// Is called when the inner or current /// gets an error. /// /// /// An that contains an event data associated with /// an inner event. /// protected virtual void OnError (ErrorEventArgs e) { } /// /// Is called when the inner receives a data frame. /// /// /// A that contains an event data associated with /// an inner event. /// protected virtual void OnMessage (MessageEventArgs e) { } /// /// Is called when the WebSocket connection has been established. /// protected virtual void OnOpen () { } /// /// Validates the cookies used in the WebSocket connection request. /// /// /// This method is called when the inner validates /// the WebSocket connection request. /// /// /// true if the cookies is valid; otherwise, false. /// The default returns true. /// /// /// A that contains a collection of the HTTP Cookies /// to validate. /// /// /// A that receives the HTTP Cookies to send to the client. /// protected virtual bool ValidateCookies (CookieCollection request, CookieCollection response) { return true; } #endregion #region Public Methods /// /// Sends a Ping to the client of the current instance. /// /// /// true if the current instance receives a Pong /// from the client in a time; otherwise, false. /// public bool Ping () { return IsBound ? _websocket.Ping () : false; } /// /// Sends a Ping with the specified to the client of /// the current instance. /// /// /// true if the current instance receives a Pong /// from the client in a time; otherwise, false. /// /// /// A that contains a message to send. /// public bool Ping (string message) { return IsBound ? _websocket.Ping (message) : false; } /// /// Sends a binary to the client of the current /// instance. /// /// /// An array of that contains a binary data to send. /// public virtual void Send (byte [] data) { if (IsBound) _websocket.Send (data); } /// /// Sends a text to the client of the current /// instance. /// /// /// A that contains a text data to send. /// public virtual void Send (string data) { if (IsBound) _websocket.Send (data); } /// /// Sends a binary to the client of the current /// instance asynchronously. /// /// /// An array of that contains a binary data to send. /// /// /// An delegate that references the method(s) called when /// the asynchronous operation completes. /// public virtual void SendAsync (byte [] data, Action completed) { if (IsBound) _websocket.SendAsync (data, completed); } /// /// Sends a text to the client of the current /// instance asynchronously. /// /// /// A that contains a text data to send. /// /// /// An delegate that references the method(s) called when /// the asynchronous operation completes. /// public virtual void SendAsync (string data, Action completed) { if (IsBound) _websocket.SendAsync (data, completed); } /// /// Starts the current instance. /// public void Start () { if (IsBound) _websocket.Connect (); } /// /// Stops the current instance. /// public void Stop () { if (IsBound) _websocket.Close (); } /// /// Stops the current instance with the specified /// and . /// /// /// A that contains a status code indicating the reason for stop. /// /// /// A that contains the reason for stop. /// public void Stop (ushort code, string reason) { if (IsBound) _websocket.Close (code, reason); } /// /// Stops the current instance with the specified /// and . /// /// /// One of the values that indicates a status code /// indicating the reason for stop. /// /// /// A that contains the reason for stop. /// public void Stop (CloseStatusCode code, string reason) { if (IsBound) _websocket.Close (code, reason); } #endregion } }