Skip to content
Merged
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
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# DresUnityInterface

---
** ATTENTION **
** The unity interface points to version 1.3 of DRES, which is behind the current version v2.0.0-RC1""
---

An interface for [DRES](https://github.com/dres-dev/DRES), meant to be used in [Unity](https://unity.com/).

## Usage / Installation
Expand Down
Binary file modified Runtime/Libs/Dev.Dres.ClientApi.dll
Binary file not shown.
6,703 changes: 5,799 additions & 904 deletions Runtime/Libs/Dev.Dres.ClientApi.xml

Large diffs are not rendered by default.

86 changes: 74 additions & 12 deletions Runtime/Scripts/Dres/UnityClient/DresClient.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dev.Dres.ClientApi.Model;
using UnityEditor;
using JetBrains.Annotations;

namespace Dres.Unityclient
{
Expand All @@ -15,7 +16,18 @@ public class DresClient
/// <summary>
/// The user state, available after <see cref="Login"/>.
/// </summary>
public UserDetails UserDetails;
public ApiUser UserDetails { get; private set; }

/// <summary>
/// List of the available evaluations for the current user.
/// Must be updated manually with <see cref="UpdateEvaluations"/> before use.
/// </summary>
public List<ApiClientEvaluationInfo> EvaluationInfo { get; private set; }

/// <summary>
/// The currently selected evaluation. Used for submissions.
/// </summary>
public ApiClientEvaluationInfo CurrentEvaluation { get; private set; }

/// <summary>
/// Login to DRES with the currently loaded credentials.
Expand All @@ -27,27 +39,77 @@ public async Task Login()
UserDetails = await DresWrapper.Login(config.user, config.password);
}


/// <summary>
/// Updates the list of available evaluations for the current user.
/// </summary>
/// <returns>List of available evaluations</returns>
public async Task<List<ApiClientEvaluationInfo>> UpdateEvaluations()
{
EvaluationInfo = await DresWrapper.ListClientEvaluations(UserDetails.SessionId);
return EvaluationInfo;
}

/// <summary>
/// Sets the current evaluation to the one with the given id.
/// </summary>
/// <param name="evaluationId">The id of the evaluation to set as current</param>
/// <returns>True if the evaluation was found and set, false otherwise</returns>
public bool SetCurrentEvaluation(string evaluationId)
{
CurrentEvaluation = EvaluationInfo.Find(evaluation => evaluation.Id == evaluationId);
return CurrentEvaluation != null;
}

/// <summary>
/// Submits the given item (and optionally start & end information) to the DRES instance as current user.
/// </summary>
/// <param name="item">The item name or identifier to submit</param>
/// <param name="start">Optional, the item's start time</param>
/// <param name="end">Optional, the item's end time</param>
/// <param name="evaluationId">Manual override of the evaluation ID of the currently set evaluation.</param>
/// <returns>The success / failure state of the operation</returns>
public Task<SuccessfulSubmissionsStatus> SubmitResultV2(string item, long? start = null, long? end = null,
[CanBeNull] string evaluationId = null)
{
evaluationId ??= CurrentEvaluation.Id;
return DresWrapper.SubmitV2(UserDetails.SessionId, evaluationId, item, start, end);
}

/// <summary>
/// Submits the given text to the DRES instance as current user
/// </summary>
/// <param name="text">The text to submit (this can be anything).</param>
/// <param name="evaluationId">Manual override of the evaluation ID of the currently set evaluation.</param>
/// <returns>The success / failure state of the operation</returns>
public Task<SuccessfulSubmissionsStatus> SubmitTextualResultV2(string text, [CanBeNull] string evaluationId = null)
{
evaluationId ??= CurrentEvaluation.Id;
return DresWrapper.SubmitTextV2(UserDetails.SessionId, evaluationId, text);
}


/// <summary>
/// Submits the given item (and optionally frame informaiton) to the DRES instance as current user.
/// </summary>
/// <param name="item">The item name or identifier to submit</param>
/// <param name="frame">Optional, the item's frame number. This can likely be omitted, if there is no such
/// concept as frames for the given item (e.g. for videos, a frame is reasonable while for images it isn't.</param>
/// <returns>The success / failure state of the operation</returns>
public async Task<SuccessfulSubmissionsStatus> SubmitResult(string item, int? frame = null)
[Obsolete("Obsolete")]
public Task<SuccessfulSubmissionsStatus> SubmitResult(string item, int? frame = null)
{
return await DresWrapper.Submit(item, UserDetails.SessionId, frame);
return DresWrapper.Submit(item, UserDetails.SessionId, frame);
}

/// <summary>
/// Submits the given text to the DRES instance as current user
/// </summary>
/// <param name="text">The text to submit (this can be anything).</param>
/// <returns>The success / failure state of the operation</returns>
public async Task<SuccessfulSubmissionsStatus> SubmitTextualResult(string text)
[Obsolete("Obsolete")]
public Task<SuccessfulSubmissionsStatus> SubmitTextualResult(string text)
{
return await DresWrapper.SubmitText(text, UserDetails.SessionId);
return DresWrapper.SubmitText(text, UserDetails.SessionId);
}

/// <summary>
Expand All @@ -61,10 +123,10 @@ public async Task<SuccessfulSubmissionsStatus> SubmitTextualResult(string text)
/// <param name="results">The results to log</param>
/// <param name="events">The events associated with these results</param>
/// <returns>The success / failure state of the operation</returns>
public async Task<SuccessStatus> LogResults(long timestamp, string sortType, string resultSetAvailability,
public Task<SuccessStatus> LogResults(long timestamp, string sortType, string resultSetAvailability,
List<QueryResult> results, List<QueryEvent> events)
{
return await DresWrapper.LogResults(timestamp, sortType, resultSetAvailability, results, events,
return DresWrapper.LogResults(timestamp, sortType, resultSetAvailability, results, events,
UserDetails.SessionId);
}

Expand All @@ -76,9 +138,9 @@ public async Task<SuccessStatus> LogResults(long timestamp, string sortType, str
/// <param name="timestamp">The client side timestamp of this log</param>
/// <param name="events">The events to log</param>
/// <returns>The success / failure state of the operation</returns>
public async Task<SuccessStatus> LogQueryEvents(long timestamp, List<QueryEvent> events)
public Task<SuccessStatus> LogQueryEvents(long timestamp, List<QueryEvent> events)
{
return await DresWrapper.LogQueryEvents(timestamp, events, UserDetails.SessionId);
return DresWrapper.LogQueryEvents(timestamp, events, UserDetails.SessionId);
}
}
}
92 changes: 74 additions & 18 deletions Runtime/Scripts/Dres/UnityClient/DresWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Dev.Dres.ClientApi.Api;
using Dev.Dres.ClientApi.Client;
Expand All @@ -14,39 +15,92 @@ namespace Dres.Unityclient
/// </summary>
internal static class DresWrapper
{

internal static readonly EvaluationClientApi EvaluationClientApi = new(DresConfigManager.Instance.ApiConfiguration);

/// <summary>
/// The deliberately single Logging Api instance of DRES. Used to send logs to DRES
/// </summary>
internal static readonly LogApi LogApi = new LogApi(DresConfigManager.Instance.ApiConfiguration);
internal static readonly LogApi LogApi = new(DresConfigManager.Instance.ApiConfiguration);

/// <summary>
/// The deliberately single Status Api instance of DRES. Used to get the status of DRES
/// </summary>
internal static readonly StatusApi StatusApi = new StatusApi(DresConfigManager.Instance.ApiConfiguration);
internal static readonly StatusApi StatusApi = new(DresConfigManager.Instance.ApiConfiguration);

/// <summary>
/// The deliberately single Submission Api instance of DRES. Used to submit media items during competitions to DRES:
/// </summary>
internal static readonly SubmissionApi SubmissionApi = new SubmissionApi(DresConfigManager.Instance.ApiConfiguration);
internal static readonly SubmissionApi SubmissionApi = new(DresConfigManager.Instance.ApiConfiguration);

/// <summary>
/// The deliberately single User Api instance of DRES. Used to log into DRES and retrieve the session id of the user.
/// </summary>
internal static readonly UserApi UserApi = new UserApi(DresConfigManager.Instance.ApiConfiguration);
internal static readonly UserApi UserApi = new(DresConfigManager.Instance.ApiConfiguration);

/// <summary>
/// Login to DRES with given username and password.
/// The login state (i.e. the <see cref="Dev.Dres.ClientApi.Model.UserDetails"/>) are not kept
/// The login state (i.e. the <see cref="Dev.Dres.ClientApi.Model.ApiUser"/>) are not kept
/// and have to be managed by the caller.
/// </summary>
/// <param name="user">The DRES username</param>
/// <param name="password">The DRES password</param>
/// <returns>The login state on success.</returns>
/// <exception cref="ApiException">If the config has no credentials set and no credentials file exists</exception>
internal static async Task<UserDetails> Login(string user, string password)
internal static Task<ApiUser> Login(string user, string password)
{
var loginRequest = new LoginRequest(user, password);
return await UserApi.PostApiV1LoginAsync(loginRequest);
return UserApi.PostApiV2LoginAsync(loginRequest);
}

internal static Task<List<ApiClientEvaluationInfo>> ListClientEvaluations(string session)
{
return EvaluationClientApi.GetApiV2ClientEvaluationListAsync(session);
}

internal static Task<ApiTaskTemplateInfo> GetTaskInfo(string evaluationId, string session)
{
return EvaluationClientApi.GetApiV2ClientEvaluationCurrentTaskByEvaluationIdAsync(evaluationId, session);
}

/// <summary>
/// Submits an item to the DRES endpoint using the DRES API v2.
/// </summary>
/// <param name="session">The session ID to which this submission belongs</param>
/// <param name="evaluationId">The evaluation ID to which this submission belongs</param>
/// <param name="item">The name of the item (or identifier) to submit</param>
/// <param name="start">The optional start (in milliseconds) of the submitted item</param>
/// <param name="end">The optional end (in milliseconds) of the submitted item</param>
/// <returns>The submission state on success / failure.</returns>
internal static Task<SuccessfulSubmissionsStatus> SubmitV2(string session, string evaluationId, string item, long? start = null,
long? end = null)
{
var answerSets = new List<ApiClientAnswerSet>
{
new(answers: new List<ApiClientAnswer>
{
new(mediaItemName: item, start: start.GetValueOrDefault(), end: end.GetValueOrDefault())
})
};
var apiClientSubmission = new ApiClientSubmission(answerSets);
return SubmissionApi.PostApiV2SubmitByEvaluationIdAsync(evaluationId, apiClientSubmission, session);
}

/// <summary>
/// Submits text to the DRES endpoint using the DRES API v2.
/// </summary>
/// <param name="session">The session ID to which this submission belongs</param>
/// <param name="evaluationId">The evaluation ID to which this submission belongs</param>
/// <param name="text">The text to submit</param>
/// <returns>The submission state on success / failure.</returns>
internal static Task<SuccessfulSubmissionsStatus> SubmitTextV2(string session, string evaluationId, string text)
{
var answerSets = new List<ApiClientAnswerSet> { new(answers: new List<ApiClientAnswer> { new(text: text) }) };
var apiClientSubmission = new ApiClientSubmission(answerSets);
return SubmissionApi.PostApiV2SubmitByEvaluationIdAsync(evaluationId, apiClientSubmission, session);
}

// TODO: Once the functionality of the new API is confirmed, implement bulk submission

/// <summary>
/// Submits an item to the DRES endpoint.
/// Submissions are only allowed during active competitions (inferred from the given sesssion id)
Expand All @@ -57,11 +111,12 @@ internal static async Task<UserDetails> Login(string user, string password)
/// If no notion of frames exist for the item, this can likely be omitted.</param>
/// <returns>The submission state on success / failure.</returns>
/// <exception cref="ApiException">A 404 if there is no ongoing competition for this session, a 403 if there is no such user</exception>
internal static async Task<SuccessfulSubmissionsStatus> Submit(string item, string session, int? frame = null)
[Obsolete("Obsolete")]
internal static Task<SuccessfulSubmissionsStatus> Submit(string item, string session, int? frame = null)
{
return await SubmissionApi.GetApiV1SubmitAsync(item: item, frame: frame, session: session);
return SubmissionApi.GetApiV1SubmitAsync(item: item, frame: frame, session: session);
}

/// <summary>
/// Submits given TEXT to the DRES endpoint.
/// Submissions are only allowed during active competitions (inferred from the given sesssion id)
Expand All @@ -70,9 +125,10 @@ internal static async Task<SuccessfulSubmissionsStatus> Submit(string item, stri
/// <param name="session">The session id to which this submission belongs</param>
/// <returns>The submission state on success / failure.</returns>
/// <exception cref="ApiException">A 404 if there is no ongoing competition for this session, a 403 if there is no such user</exception>
internal static async Task<SuccessfulSubmissionsStatus> SubmitText(string text, string session)
[Obsolete("Obsolete")]
internal static Task<SuccessfulSubmissionsStatus> SubmitText(string text, string session)
{
return await SubmissionApi.GetApiV1SubmitAsync(text: text, session: session);
return SubmissionApi.GetApiV1SubmitAsync(text: text, session: session);
}


Expand All @@ -89,11 +145,11 @@ internal static async Task<SuccessfulSubmissionsStatus> SubmitText(string text,
/// <param name="session">The session id to which this log belongs</param>
/// <returns>The state of success / failure of the log sending.</returns>
/// <exception cref="ApiException">A 404 if there is no ongoing competition for this session, a 403 if there is no such user</exception>
internal static async Task<SuccessStatus> LogResults(long timestamp, string sortType, string resultSetAvailability,
internal static Task<SuccessStatus> LogResults(long timestamp, string sortType, string resultSetAvailability,
List<QueryResult> results, List<QueryEvent> events, string session)
{
var resultLog = new QueryResultLog(timestamp, sortType, resultSetAvailability, results, events);
return await LogApi.PostApiV1LogResultAsync(session, resultLog);
return LogApi.PostApiV2LogResultAsync(session, resultLog);
}

/// <summary>
Expand All @@ -106,10 +162,10 @@ internal static async Task<SuccessStatus> LogResults(long timestamp, string sort
/// <param name="session">The session id to which this log belongs</param>
/// <returns>The state of success / failure of the log sending.</returns>
/// <exception cref="ApiException">A 404 if there is no ongoing competition for this session, a 403 if there is no such user</exception>
internal static async Task<SuccessStatus> LogQueryEvents(long timestamp, List<QueryEvent> events, string session)
internal static Task<SuccessStatus> LogQueryEvents(long timestamp, List<QueryEvent> events, string session)
{
var queryEventLog = new QueryEventLog(timestamp, events);
return await LogApi.PostApiV1LogQueryAsync(session, queryEventLog);
return LogApi.PostApiV2LogQueryAsync(session, queryEventLog);
}
}
}
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import org.apache.tools.ant.taskdefs.condition.Os

/* Get the openapi generator plugin */
plugins {
id "org.openapi.generator" version "4.3.1"
id "org.openapi.generator" version "6.4.0"
}

/* Setup OpenApi Specs (OAS): Defaults to default.*/
/* Additional, sensible settings:
+ http://localhost:8080/client-oas.json // Local DRES
+ https://raw.githubusercontent.com/dres-dev/DRES/master/doc/oas-client.json // When oas-client is released
*/
def dresOAS = "https://raw.githubusercontent.com/dres-dev/DRES/1.0/doc/oas-client.json"
def dresOAS = "https://raw.githubusercontent.com/dres-dev/DRES/2.0.0-RC1/doc/oas-client.json"
/* If gradle gets 'oas' argument (with -Poas="path/to/OAS"), take these */
if(project.hasProperty('oas')){
dresOAS = oas
Expand Down Expand Up @@ -68,9 +68,9 @@ task modex(type: Exec){
task deployLibs(type: Copy){
from(file("$rootDir/Generated/bin"))
into(file("$rootDir/Runtime/Libs"))
rename("RestSharp.dll", "RestSharp.Dres.dll")
rename("Newtonsoft.Json.dll", "Newtonsoft.Json.Dres.dll")
rename("JsonSubTypes.dll", "JsonSubTypes.Dres.dll")
rename("RestSharp.dll", "RestSharp." + dllName + ".dll")
rename("Newtonsoft.Json.dll", "Newtonsoft.Json." + dllName + ".dll")
rename("JsonSubTypes.dll", "JsonSubTypes." + dllName + ".dll")
}

/* Copy the mandatory link.xml */
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dev.dres.unityclient",
"version": "1.1.0",
"version": "1.2.0",
"displayName": "DRES Unity Client",
"description": "An all-unity client for [DRES](https://github.com/dres-dev/DRES)",
"unity": "2020.3",
Expand Down