You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
11 KiB
316 lines
11 KiB
using Newtonsoft.Json; |
|
using System; |
|
using System.Diagnostics; |
|
using System.Linq; |
|
using System.Net; |
|
using System.Net.Http; |
|
using System.Net.Http.Headers; |
|
using System.Reflection.Metadata.Ecma335; |
|
using System.Runtime.CompilerServices; |
|
using System.Text; |
|
using System.Text.RegularExpressions; |
|
using System.Threading.Tasks; |
|
|
|
namespace MatrixDotNetLib |
|
{ |
|
public class MatrixSessionManager |
|
{ |
|
/// <summary> |
|
/// Gets or sets the authentication token. |
|
/// </summary> |
|
public string Token { get; set; } |
|
|
|
/// <summary> |
|
/// Gets or sets the Matrix homeserver FQDN. |
|
/// </summary> |
|
public string Server { get; set; } |
|
|
|
/// <summary> |
|
/// Gets or sets the login session as a MatrixLoginResponse object. |
|
/// </summary> |
|
public MatrixLoginResponse LoginSession { get; set; } |
|
|
|
/// <summary> |
|
/// Logs the user in with specified server and credentials. |
|
/// </summary> |
|
/// <param name="server">Required</param> |
|
/// <param name="user">Required</param> |
|
/// <param name="pass">Required</param> |
|
/// <param name="device">Optional</param> |
|
/// <returns></returns> |
|
public MatrixLoginResponse Login(string server, string user, string pass, string device = "") |
|
{ |
|
// set the object's server |
|
this.Server = server; |
|
|
|
MatrixLoginIdentifier userId = new MatrixLoginIdentifier() |
|
{ |
|
IdType = "m.id.user", |
|
User = user |
|
}; |
|
|
|
MatrixLoginRequest theRequest = new MatrixLoginRequest() |
|
{ |
|
Password = pass, |
|
Identifier = userId, |
|
LoginType = "m.login.password" |
|
}; |
|
|
|
if (device.Length > 0) |
|
{ |
|
theRequest.DeviceId = device; |
|
} |
|
|
|
// serialize object into JSON |
|
string requestJson = JsonConvert.SerializeObject(theRequest); |
|
|
|
string responseJson = ApiResult(MatrixApi.User.Login, httpAction.POST, requestJson); |
|
|
|
MatrixLoginResponse response = JsonConvert.DeserializeObject<MatrixLoginResponse>(responseJson); |
|
|
|
// we're logged in, so set the object's token |
|
this.Token = response.Token; |
|
|
|
// also set the object's session data |
|
this.LoginSession = response; |
|
|
|
return response; |
|
} |
|
|
|
/// <summary> |
|
/// Gets the logged-in user's currently-joined rooms. |
|
/// </summary> |
|
/// <returns></returns> |
|
public MatrixUserRooms GetRooms() |
|
{ |
|
string responseJson = ApiResult(MatrixApi.User.Rooms, httpAction.GET); |
|
|
|
return (MatrixUserRooms)JsonConvert.DeserializeObject<MatrixUserRooms>(responseJson); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the aliases for the given (string)roomId |
|
/// </summary> |
|
/// <param name="roomId">Full string ID (not alias) of a room</param> |
|
/// <returns></returns> |
|
public MatrixRoomAliases GetRoomAliases(string roomId) |
|
{ |
|
MatrixApiEntities entities = new MatrixApiEntities() { RoomId = roomId }; |
|
string responseJson = ApiResult(MatrixApi.Room.Aliases, httpAction.GET, entities: entities); |
|
|
|
return (MatrixRoomAliases)JsonConvert.DeserializeObject<MatrixRoomAliases>(responseJson); |
|
} |
|
|
|
/// <summary> |
|
/// Joins the user to the given room by (string)roomId |
|
/// </summary> |
|
/// <param name="roomId">Full string ID (not alias) of a room</param> |
|
/// <returns></returns> |
|
public MatrixRoom JoinRoom(string roomId) |
|
{ |
|
// create entity object |
|
MatrixApiEntities apiEntities = new MatrixApiEntities() { RoomId = roomId }; |
|
|
|
string responseJson = ApiResult(MatrixApi.Room.Join, httpAction.POST, entities: apiEntities); |
|
|
|
return (MatrixRoom)JsonConvert.DeserializeObject<MatrixRoom>(responseJson); |
|
} |
|
|
|
public MatrixRoomDirectory GetPublicRooms(int limit = 0, string page = null, string server = null) |
|
{ |
|
string[] querystring = { }; |
|
|
|
if (limit > 0) |
|
{ |
|
querystring.Append("limit=" + limit); |
|
} |
|
|
|
if (page != null) |
|
{ |
|
querystring.Append("since=" + page); |
|
} |
|
|
|
if (server != null) |
|
{ |
|
querystring.Append("server=" + server); |
|
} |
|
|
|
string responseJson = ""; |
|
|
|
if (querystring.Count() > 0) |
|
{ |
|
string qs = string.Join("&", querystring); |
|
|
|
responseJson = ApiResult(MatrixApi.Server.RoomList, httpAction.GET, query: qs); |
|
} |
|
else |
|
{ |
|
responseJson = ApiResult(MatrixApi.Server.RoomList, httpAction.GET); |
|
} |
|
|
|
return (MatrixRoomDirectory)JsonConvert.DeserializeObject<MatrixRoomDirectory>(responseJson); |
|
} |
|
|
|
public enum httpAction |
|
{ |
|
DELETE, |
|
GET, |
|
POST, |
|
PUT |
|
} |
|
|
|
public string ApiResult(string api, httpAction action = httpAction.GET, string json = null, MatrixApiEntities entities = null, string query = null) |
|
{ |
|
// simplest implementation |
|
// might not work for UWP |
|
// sauce: https://stackoverflow.com/questions/5527316/how-to-set-the-content-of-an-httpwebrequest-in-c |
|
|
|
// replace all entities in param |
|
|
|
string url = "https://" + this.Server + api; |
|
|
|
HttpClient client = new HttpClient(); |
|
client.BaseAddress = new Uri(url); |
|
|
|
// if an access token exists, create a bearer authorization header |
|
if (this.Token != null) |
|
{ |
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", this.Token); |
|
} |
|
|
|
// init empty string |
|
string responseString = ""; |
|
|
|
// DELETE: replace all entities in uri with values in param |
|
// GET: replace all entities in uri with values in param |
|
// POST: replace entities, create content from json |
|
// PUT: replace entitites, create content from json |
|
|
|
|
|
if (entities != null) |
|
{ |
|
// check if any populated entity property exists in the url |
|
// find {...} in url |
|
// replace with values from entity object |
|
string matchPattern = @"\{([A-Za-z]+)\}"; |
|
Regex rgx = new Regex(matchPattern); |
|
|
|
MatrixUtil util = new MatrixUtil(); |
|
|
|
foreach (Match match in rgx.Matches(url)) |
|
{ |
|
string oldVal = match.Value; |
|
string prop = match.Groups[1].Value; |
|
|
|
// check if property exists in entity list |
|
try |
|
{ |
|
// get value of property through GetType().GetProperty().GetValue() |
|
// sauce: https://www.techrepublic.com/article/applied-reflection-dynamically-accessing-properties-of-a-class-at-runtime/ |
|
string newVal = WebUtility.UrlEncode(entities.GetType().GetProperty(prop).GetValue(entities).ToString()); |
|
|
|
// return URL with entities replaced and URL-encoded |
|
url = url.Replace(oldVal, newVal); |
|
} |
|
catch |
|
{ |
|
// shit broke |
|
} |
|
} |
|
} |
|
|
|
HttpResponseMessage responseMessage = new HttpResponseMessage(); |
|
|
|
if (json != null) |
|
{ |
|
// create HTTP request body from JSON string |
|
HttpContent requestContent = new StringContent(json, Encoding.UTF8, "application/json"); |
|
|
|
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); |
|
|
|
switch (action) |
|
{ |
|
case httpAction.POST: |
|
responseMessage = client.PostAsync(url, requestContent).Result; |
|
break; |
|
case httpAction.PUT: |
|
responseMessage = client.PutAsync(url, requestContent).Result; |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
// no message body, so this must be a GET or DELETE operation |
|
switch (action) |
|
{ |
|
case httpAction.DELETE: |
|
responseMessage = client.DeleteAsync(url).Result; |
|
break; |
|
case httpAction.GET: |
|
responseMessage = client.GetAsync(url).Result; |
|
break; |
|
} |
|
} |
|
|
|
responseString = responseMessage.Content.ReadAsStringAsync().Result; |
|
|
|
if (responseString.Contains("errcode")) |
|
{ |
|
// deserialize into error object |
|
MatrixError error = JsonConvert.DeserializeObject<MatrixError>(responseString); |
|
|
|
// convert error object to a string |
|
string errMsg = error.ErrorCode + ": " + error.ErrorMessage; |
|
errMsg += "\n\nAPI accessed : " + url; |
|
errMsg += "\nToken Used : " + (this.Token.Length > 0 ? "yes" : "no"); |
|
|
|
// throw exception (can be caught and handled gracefully) |
|
throw new Exception(errMsg); |
|
} |
|
else if (responseMessage.StatusCode != HttpStatusCode.OK) |
|
{ |
|
// web server responded with an HTTP status code other than 200 OK |
|
string errMsg = "Server returned " + (int)responseMessage.StatusCode + ": " + responseMessage.StatusCode.ToString(); |
|
errMsg += "\n\nAPI accessed : " + url; |
|
errMsg += "\nToken Used : " + (this.Token.Length > 0 ? "yes" : "no"); |
|
throw new Exception(errMsg); |
|
} |
|
else |
|
{ |
|
return responseString; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
//// simplest implementation |
|
//// might not work for UWP |
|
//// sauce: https://stackoverflow.com/questions/5527316/how-to-set-the-content-of-an-httpwebrequest-in-c |
|
//HttpContent requestContent = new StringContent(requestJson, Encoding.UTF8, "application/json"); |
|
|
|
//HttpClient client = new HttpClient(); |
|
//client.BaseAddress = new Uri(loginUrl); |
|
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); |
|
|
|
//HttpResponseMessage responseMessage = client.PostAsync(loginUrl, requestContent).Result; |
|
//string responseString = responseMessage.Content.ReadAsStringAsync().Result; |
|
|
|
//if(responseString.Contains("errcode")) |
|
//{ |
|
// // deserialize into error object |
|
// MatrixError error = JsonConvert.DeserializeObject<MatrixError>(responseString); |
|
|
|
// // convert error object to a string |
|
// string errMsg = error.ErrorCode + ": " + error.ErrorMessage; |
|
|
|
// // throw exception (can be caught and handled gracefully) |
|
// throw new Exception(errMsg); |
|
//} |
|
//else |
|
//{ |
|
// MatrixLoginResponse response = JsonConvert.DeserializeObject<MatrixLoginResponse>(responseString); |
|
|
|
// return response; |
|
//} |