static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += (_, eventArgs) => { var exception = eventArgs.ExceptionObject as Exception; string message = string.Format("Unhandled exception: {0}: {1} \r\n{2}", exception.GetType().ToString(), exception.Message, exception.StackTrace); LogTo.Fatal(message); HipchatSender.SendNotification("Server errors", message, RoomColors.Random); }; try { LogTo.Debug("======================= STARTING =========================="); IKernel kernel = new StandardKernel(); // Factories kernel.Bind <IChannelHandlerFactory>().ToFactory(); kernel.Bind <IChatProviderFactory>().ToFactory(); // Singletons kernel.Bind <RedisProvider>().ToSelf().InSingletonScope(); // Standard lifetime kernel.Bind <IPlaylistProvider>().To <SortedPlaylistProvider>(); kernel.Bind <IMQTTSettings>().To <ServerMqttSettings>(); var server = kernel.Get <Server>(); server.Run(); var heartbeat = TimeSpan.FromMinutes(3); while (true) { File.WriteAllText("sovndserver.heartbeat", Time.Timestamp().ToString()); Thread.Sleep(heartbeat); } } finally { LogTo.Debug("========================= DEAD ============================"); } }
public Server(IMQTTSettings settings, IChannelHandlerFactory chf, ServerSpotifyAuth spot, RedisProvider redis) : base(settings.Broker, settings.Port, settings.Username, settings.Password) { _spot = spot; _redisconnection = redis.redis; _redis = _redisconnection.GetDatabase(); LogTo.Trace("Initializing routes"); ////// // User messages ////// /// // Handle user-channel interaction On["/user/{username}/{channel}/songs/{songid}"] = msg => { switch ((string)msg.Message) { case "vote": AddVote(msg.channel, msg.songid, msg.username); break; case "unvote": RemoveVote(msg.channel, msg.songid, msg.username); break; case "report": ReportSong(msg.channel, msg.songid, msg.username); break; case "remove": RemoveSong(msg.channel, msg.songid, msg.username); break; case "block": BlockSong(msg.channel, msg.songid, msg.username); break; default: LogTo.Warn("[{0}] Invalid command: {1}: {2}, by {3}", (string)msg.channel, (string)msg.Topic, (string)msg.Message, (string)msg.username); break; } }; // Handle channel registration On["/user/{username}/register/{channel}"] = _ => { // TODO Separate channel name from ID Channel channel = JsonConvert.DeserializeObject <Channel>(_.Message); if (channel == null || string.IsNullOrWhiteSpace(channel.Name)) { LogTo.Warn("Rejected invalid channel JSON from {0} for channel {1}: {2}", (string)_.username, (string)_.channel, (string)_.Message); return; } LogTo.Info("[{0}] {1} sent channel data: {2}", (string)_.channel, (string)_.username, (string)_.Message); if (!_redis.KeyExists(GetChannelNameID(_.channel))) { // Channel doesn't exist yet LogTo.Info("[{0}] Setting up new channel for {1}", (string)_.channel, (string)_.username); _redis.StringSet(GetChannelNameID(_.channel), channel.Name); _redis.StringSet(GetChannelDescriptionID(_.channel), channel.Description); _redis.SetAdd(GetChannelModeratorID(_.channel), _.username); } else { // Channel exists if (!_redis.SetContains(GetChannelModeratorID(_.channel), _.username)) { LogTo.Error("[{0}] Error: User {1} not a moderator of channel", (string)_.channel, (string)_.username); return; } LogTo.Info("[{0}] changing existing channel for {1}", (string)_.channel, (string)_.username); _redis.StringSet(GetChannelNameID(_.channel), channel.Name); _redis.StringSet(GetChannelDescriptionID(_.channel), channel.Description); } Publish(string.Format("/{0}/info", _.channel), _.Message, true); }; // Handle user chat messages On["/user/{username}/{channel}/chat"] = _ => { LogTo.Trace("{0}->{1}: {2}", (string)_.username, (string)_.channel, (string)_.Message); // TODO [LOW] Allow moderators to mute users if (channels.ContainsKey(_.channel)) { var topic = string.Format("/{0}/chat", _.channel); var message = new ChatMessage { message = _.Message, username = _.username, time = Time.Timestamp() }; var messageJson = JsonConvert.SerializeObject(message); Publish(topic, messageJson); HipchatSender.SendNotification(_.channel, string.Format("{0}: {1}", message.username, message.message), RoomColors.Gray); } else { LogTo.Debug("Chat was for invalid channel"); } }; ////// // Channel messages ////// // TODO: This should be separate from above // Handle channel info On["/{channel}/info"] = _ => { LogTo.Info("[{0}] Got info: {1}", (string)_.channel, (string)_.Message); Channel channel = JsonConvert.DeserializeObject <Channel>(_.Message); if (!channels.ContainsKey(_.channel)) { ChannelHandler channelHandler = chf.CreateChannelHandler(_.channel); channelHandler.Subscribe(); channels[_.channel] = channelHandler; StartChannelScheduler(channelHandler); } }; }