Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/ISoulseekClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,15 @@ public interface ISoulseekClient : IDisposable, IDiagnosticGenerator
/// <exception cref="SoulseekClientException">Thrown when an exception is encountered during the operation.</exception>
Task SetStatusAsync(UserPresence status, CancellationToken? cancellationToken = null);

/// <summary>
/// Asynchronously informs the server of the user's liked and disliked interests.
/// </summary>
/// <param name="likes">A collection of liked interests.</param>
/// <param name="dislikes">A collection of disliked interests.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Task"/> representing the asynchronous operation.</returns>
Task SetInterestsAsync(IEnumerable<string> likes, IEnumerable<string> dislikes, CancellationToken? cancellationToken = null);

/// <summary>
/// Asynchronously starts receiving public chat messages.
/// </summary>
Expand Down
53 changes: 53 additions & 0 deletions src/Messaging/Messages/Server/HatedInterestAddCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// <copyright file="HatedInterestAddCommand.cs" company="JP Dillingham">
// Copyright (c) JP Dillingham. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see https://www.gnu.org/licenses/.
// </copyright>

namespace Soulseek.Messaging.Messages.Server
{
using Soulseek.Messaging;

/// <summary>
/// Adds a disliked interest to the user's profile on the server.
/// </summary>
internal class HatedInterestAddCommand : IOutgoingMessage
{
/// <summary>
/// Initializes a new instance of the <see cref="HatedInterestAddCommand"/> class.
/// </summary>
/// <param name="interest">The disliked interest to add.</param>
public HatedInterestAddCommand(string interest)
{
Interest = interest;
}

/// <summary>
/// Gets the disliked interest to add.
/// </summary>
public string Interest { get; }

/// <summary>
/// Constructs a <see cref="byte"/> array from this message.
/// </summary>
/// <returns>The constructed byte array.</returns>
public byte[] ToByteArray()
{
return new MessageBuilder()
.WriteCode((MessageCode.Server)117)
.WriteString(Interest)
.Build();
}
}
}
53 changes: 53 additions & 0 deletions src/Messaging/Messages/Server/InterestAddCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// <copyright file="InterestAddCommand.cs" company="JP Dillingham">
// Copyright (c) JP Dillingham. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see https://www.gnu.org/licenses/.
// </copyright>

namespace Soulseek.Messaging.Messages.Server
{
using Soulseek.Messaging;

/// <summary>
/// Adds a liked interest to the user's profile on the server.
/// </summary>
internal class InterestAddCommand : IOutgoingMessage
{
/// <summary>
/// Initializes a new instance of the <see cref="InterestAddCommand"/> class.
/// </summary>
/// <param name="interest">The interest to add.</param>
public InterestAddCommand(string interest)
{
Interest = interest;
}

/// <summary>
/// Gets the interest to add.
/// </summary>
public string Interest { get; }

/// <summary>
/// Constructs a <see cref="byte"/> array from this message.
/// </summary>
/// <returns>The constructed byte array.</returns>
public byte[] ToByteArray()
{
return new MessageBuilder()
.WriteCode((MessageCode.Server)51)
.WriteString(Interest)
.Build();
}
}
}
65 changes: 59 additions & 6 deletions src/SoulseekClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@

namespace Soulseek
{
using Soulseek.Diagnostics;
using Soulseek.Messaging;
using Soulseek.Messaging.Handlers;
using Soulseek.Messaging.Messages;
using Soulseek.Messaging.Messages.Server;
using Soulseek.Network;
using Soulseek.Network.Tcp;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
Expand All @@ -27,12 +34,6 @@ namespace Soulseek
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Soulseek.Diagnostics;
using Soulseek.Messaging;
using Soulseek.Messaging.Handlers;
using Soulseek.Messaging.Messages;
using Soulseek.Network;
using Soulseek.Network.Tcp;

/// <summary>
/// A client for the Soulseek file sharing network.
Expand Down Expand Up @@ -2479,6 +2480,58 @@ public Task SetSharedCountsAsync(int directories, int files, CancellationToken?
}
}



/// <summary>
/// Asynchronously informs the server of the user's <paramref name="likes"/> and <paramref name="dislikes"/>.
/// </summary>
/// <param name="likes">A collection of liked interests.</param>
/// <param name="dislikes">A collection of disliked interests.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The Task representing the asynchronous operation.</returns>
/// <exception cref="InvalidOperationException">Thrown when the client is not connected or logged in.</exception>
/// <exception cref="TimeoutException">Thrown when the operation has timed out.</exception>
/// <exception cref="OperationCanceledException">Thrown when the operation has been cancelled.</exception>
/// <exception cref="SoulseekClientException">Thrown when an exception is encountered during the operation.</exception>
public async Task SetInterestsAsync(IEnumerable<string> likes, IEnumerable<string> dislikes, CancellationToken? cancellationToken = null)
{
if (!State.HasFlag(SoulseekClientStates.Connected) || !State.HasFlag(SoulseekClientStates.LoggedIn))
{
throw new InvalidOperationException($"The server connection must be connected and logged in to set interests; currently {State}.");
}

var token = cancellationToken ?? CancellationToken.None;

try
{
if (likes != null)
{
foreach (var like in likes)
{
if (string.IsNullOrWhiteSpace(like)) continue;

await ServerConnection.WriteAsync(new InterestAddCommand(like), token).ConfigureAwait(false);
}
}

if (dislikes != null)
{
foreach (var dislike in dislikes)
{
if (string.IsNullOrWhiteSpace(dislike)) continue;

await ServerConnection.WriteAsync(new HatedInterestAddCommand(dislike), token).ConfigureAwait(false);
}
}
}
catch (Exception ex) when (!(ex is OperationCanceledException) && !(ex is TimeoutException))
{
throw new SoulseekClientException($"Failed to set interests: {ex.Message}", ex);
}
}



/// <summary>
/// Asynchronously informs the server of the current online <paramref name="status"/> of the client.
/// </summary>
Expand Down