using System.Runtime.Intrinsics.X86; using LibMatrix.EventTypes.Spec.State.RoomInfo; using LibMatrix.Homeservers; using LibMatrix.Responses; using LibMatrix.RoomTypes; namespace LibMatrix.Helpers; public class RoomBuilder { public string? Type { get; set; } public string Version { get; set; } = "11"; public RoomNameEventContent Name { get; set; } = new(); public RoomTopicEventContent Topic { get; set; } = new(); public RoomAvatarEventContent Avatar { get; set; } = new(); public RoomCanonicalAliasEventContent CanonicalAlias { get; set; } = new(); public string AliasLocalPart { get; set; } = string.Empty; public bool IsFederatable { get; set; } = true; public long OwnPowerLevel { get; set; } = MatrixConstants.MaxSafeJsonInteger; public RoomJoinRulesEventContent JoinRules { get; set; } = new() { JoinRule = RoomJoinRulesEventContent.JoinRules.Public }; public RoomHistoryVisibilityEventContent HistoryVisibility { get; set; } = new() { HistoryVisibility = RoomHistoryVisibilityEventContent.HistoryVisibilityTypes.Shared }; /// /// State events to be sent *before* room access is configured. Keep this small! /// public List ImportantState { get; set; } = []; /// /// State events to be sent *after* room access is configured, but before invites are sent. /// public List InitialState { get; set; } = []; /// /// Users to invite, with optional reason /// public Dictionary Invites { get; set; } = new(); public RoomPowerLevelEventContent PowerLevels { get; init; } = new() { EventsDefault = 0, UsersDefault = 0, Kick = 50, Invite = 50, Ban = 50, Redact = 50, StateDefault = 50, NotificationsPl = new() { Room = 50 }, Users = [], Events = new Dictionary { { RoomAvatarEventContent.EventId, 50 }, { RoomCanonicalAliasEventContent.EventId, 50 }, { RoomEncryptionEventContent.EventId, 100 }, { RoomHistoryVisibilityEventContent.EventId, 100 }, { RoomNameEventContent.EventId, 50 }, { RoomPowerLevelEventContent.EventId, 100 }, { RoomServerAclEventContent.EventId, 100 }, { RoomTombstoneEventContent.EventId, 100 }, { RoomPolicyServerEventContent.EventId, 100 } } }; public async Task Create(AuthenticatedHomeserverGeneric homeserver) { var crq = new CreateRoomRequest() { PowerLevelContentOverride = new() { EventsDefault = 1000000, UsersDefault = 1000000, Kick = 1000000, Invite = 1000000, Ban = 1000000, Redact = 1000000, StateDefault = 1000000, NotificationsPl = new() { Room = 1000000 }, Users = new Dictionary() { { homeserver.WhoAmI.UserId, MatrixConstants.MaxSafeJsonInteger } }, Events = new Dictionary { { RoomAvatarEventContent.EventId, 1000000 }, { RoomCanonicalAliasEventContent.EventId, 1000000 }, { RoomEncryptionEventContent.EventId, 1000000 }, { RoomHistoryVisibilityEventContent.EventId, 1000000 }, { RoomNameEventContent.EventId, 1000000 }, { RoomPowerLevelEventContent.EventId, 1000000 }, { RoomServerAclEventContent.EventId, 1000000 }, { RoomTombstoneEventContent.EventId, 1000000 }, { RoomPolicyServerEventContent.EventId, 1000000 } } }, Visibility = "private", RoomVersion = Version }; if (!string.IsNullOrWhiteSpace(Type)) crq.CreationContent.Add("type", Type); if (!IsFederatable) crq.CreationContent.Add("m.federate", false); var room = await homeserver.CreateRoom(crq); await SetBasicRoomInfoAsync(room); await SetStatesAsync(room, ImportantState); await SetAccessAsync(room); await SetStatesAsync(room, InitialState); await SendInvites(room); return room; } private async Task SendInvites(GenericRoom room) { if (Invites.Count == 0) return; var inviteTasks = Invites.Select(async kvp => { try { await room.InviteUserAsync(kvp.Key, kvp.Value); } catch (MatrixException e) { Console.Error.WriteLine("Failed to invite {0} to {1}: {2}", kvp.Key, room.RoomId, e.Message); } }); await Task.WhenAll(inviteTasks); } private async Task SetStatesAsync(GenericRoom room, List state) { foreach (var ev in state) { await (string.IsNullOrWhiteSpace(ev.StateKey) ? room.SendStateEventAsync(ev.Type, ev.RawContent) : room.SendStateEventAsync(ev.Type, ev.StateKey, ev.RawContent)); } } private async Task SetBasicRoomInfoAsync(GenericRoom room) { if (!string.IsNullOrWhiteSpace(Name.Name)) await room.SendStateEventAsync(RoomNameEventContent.EventId, Name); if (!string.IsNullOrWhiteSpace(Topic.Topic)) await room.SendStateEventAsync(RoomTopicEventContent.EventId, Topic); if (!string.IsNullOrWhiteSpace(Avatar.Url)) await room.SendStateEventAsync(RoomAvatarEventContent.EventId, Avatar); if (!string.IsNullOrWhiteSpace(AliasLocalPart)) CanonicalAlias.Alias = $"#{AliasLocalPart}:{room.Homeserver.ServerName}"; if (!string.IsNullOrWhiteSpace(CanonicalAlias.Alias)) { await room.Homeserver.SetRoomAliasAsync(CanonicalAlias.Alias!, room.RoomId); await room.SendStateEventAsync(RoomCanonicalAliasEventContent.EventId, CanonicalAlias); } } private async Task SetAccessAsync(GenericRoom room) { PowerLevels.Users![room.Homeserver.WhoAmI.UserId] = OwnPowerLevel; await room.SendStateEventAsync(RoomPowerLevelEventContent.EventId, PowerLevels); if (!string.IsNullOrWhiteSpace(HistoryVisibility.HistoryVisibility)) await room.SendStateEventAsync(RoomHistoryVisibilityEventContent.EventId, HistoryVisibility); if (!string.IsNullOrWhiteSpace(JoinRules.JoinRuleValue)) await room.SendStateEventAsync(RoomJoinRulesEventContent.EventId, JoinRules); } } public class MatrixConstants { public const long MaxSafeJsonInteger = 9007199254740991L; // 2^53 - 1 }