package me.illusion.university.module.impl.school.data; import lombok.Getter; import me.illusion.university.communication.StoredData; import me.illusion.university.module.impl.school.communication.packet.PacketUpdateMemberData; import me.illusion.university.module.impl.school.data.data.MemberData; import me.illusion.university.module.impl.school.data.invite.InviteData; import me.illusion.university.module.impl.school.data.role.ClassPermission; import me.illusion.university.module.impl.school.data.role.ClassRole; import me.illusion.university.module.impl.school.utils.StringUtils; import java.util.*; import java.util.concurrent.CompletableFuture; @Getter public class Classroom { private final ClassroomStorage storage; private final UUID uuid; Classroom(ClassroomStorage storage, UUID uuid) { // package-private this.storage = storage; this.uuid = uuid; } public CompletableFuture saveToDatabase() { return getRawData().thenAccept(data -> { System.out.println("Saving data " + data); storage.getFetchingDatabase().store(uuid, new StoredData(uuid, data)).join(); }); } public CompletableFuture isValid() { return storage.getFetchingDatabase().fetch(uuid).thenApply(Objects::nonNull); } public CompletableFuture> getRawData() { return CompletableFuture.supplyAsync(() -> { Map data = new HashMap<>(); // data.put("uuid", uuid.toString()); data.put("display-name", getDisplayName().join()); data.put("members", getAllMembers().join()); return data; }); } public CompletableFuture removeFromCache() { return CompletableFuture.runAsync(() -> { storage.getCachingDatabase().delete(uuid.toString()).join(); }); } public CompletableFuture loadToCache() { return storage.getFetchingDatabase().fetch(uuid).thenAccept(data -> { if (data == null) return; Map contents = data.getData(); System.out.println("Fetched contents: " + contents); if (!contents.containsKey("display-name")) { // removeFromCache().join(); - No need to remove from cache, as it's not there storage.getFetchingDatabase().delete(uuid).join(); throw new IllegalStateException("Corrupted or deleted data for classroom " + uuid); // break the chain } // solve discrepancies between storage and processing layers Collection memberData = (Collection) contents.get("members"); contents.put("members", new HashSet<>(memberData)); List> futures = new ArrayList<>(); futures.add(setDisplayName((String) contents.get("display-name"))); futures.add(setAllMembers((Set) contents.get("members"))); CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); }); } public CompletableFuture getInviteCode() { return storage.getCachingDatabase().fetch(uuid.toString(), "invite-code").thenApply(o -> (String) o).thenApply((code) -> { if (code == null) { code = StringUtils.createRandomString(7); storage.getInviteCache().saveCode(new InviteData(code, uuid)).join(); storage.getCachingDatabase().store(uuid.toString(), "invite-code", code); } return code; }); } public CompletableFuture getDisplayName() { return storage.getCachingDatabase().fetch(uuid.toString(), "display-name").thenApply(o -> (String) o); } public CompletableFuture setDisplayName(String displayName) { return storage.getCachingDatabase().store(uuid.toString(), "display-name", displayName).thenRun(() -> System.out.println("Set display name to " + displayName)); } public CompletableFuture addRole(UUID uuid, ClassRole role) { return getAllMembers().thenAccept(set -> { for (MemberData memberData : set) { if (!memberData.getUuid().equals(uuid)) continue; memberData.getRoles().add(role); System.out.println("Added role " + role + " to " + uuid); System.out.println("New data: " + set); CompletableFuture.allOf( storage.getCachingDatabase().store(uuid.toString(), "members-", memberData), storage.getCachingDatabase().store(uuid.toString(), "members", set), storage.getMain().getPacketManager().send(new PacketUpdateMemberData(uuid, memberData))).join(); System.out.println("Role adding complete"); return; } System.out.println("The member " + uuid + " was not found in the classroom " + this.uuid); }).exceptionally(e -> { e.printStackTrace(); return null; }); } public CompletableFuture removeRole(UUID uuid, ClassRole role) { return getAllMembers().thenAccept(set -> { for (MemberData memberData : set) { if (!memberData.getUuid().equals(uuid)) continue; memberData.getRoles().remove(role); CompletableFuture.allOf(storage.getCachingDatabase().store(uuid.toString(), "members-", memberData), storage.getCachingDatabase().store(uuid.toString(), "members", set), storage.getMain().getPacketManager().send(new PacketUpdateMemberData(uuid, memberData))).join(); break; } System.out.println("The member " + uuid + " was not found in the classroom " + this.uuid); }); } public CompletableFuture hasRole(UUID uuid, ClassRole role) { return getMemberData(uuid).thenApply(data -> data.getRoles().contains(role)); } public CompletableFuture hasPermission(UUID uuid, ClassPermission permission) { return getMemberData(uuid).thenApply(data -> data.hasPermission(permission)); } public CompletableFuture> getAllMembers() { return storage.getCachingDatabase().fetch(uuid.toString(), "members").thenApply(o -> { if(o == null) { System.out.println("Members is null, Creating new set"); return null; } if (!(o instanceof Collection)) { System.out.println("Invalid data for members: " + o); return null; } return (Set) new HashSet<>((Collection) o); }).thenApply((data) -> { if (data == null) { data = new HashSet<>(); storage.getCachingDatabase().store(uuid.toString(), "members", data); } return data; }).exceptionally(e -> { e.printStackTrace(); return null; }); } private CompletableFuture setAllMembers(Set data) { List> futures = new ArrayList<>(); for (MemberData memberData : data) futures.add(storage.getCachingDatabase().store(uuid.toString(), "members-", memberData)); return CompletableFuture.allOf( storage.getCachingDatabase().store(uuid.toString(), "members", data), CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) ); } public CompletableFuture addMember(UUID uuid) { MemberData data = new MemberData(uuid, new HashSet<>()); return CompletableFuture.allOf( storage.getCachingDatabase().store(this.uuid.toString(), "members-" + uuid, data) .thenRun(() -> System.out.println("Stored member data")), storage.getMain().getPacketManager().send(new PacketUpdateMemberData(uuid, data)) .thenRun(() -> System.out.println("Sent packet to update member data")), storage.fetchPlayerData(uuid).thenApply(playerData -> playerData.addClassroom(this.uuid)), getAllMembers().thenApply((members) -> { members.add(data); System.out.println("Member set: " + members); return members; }).thenApply((members) -> storage.getCachingDatabase().store(this.uuid.toString(), "members", members)) .thenRun(() -> System.out.println("Stored member data to set"))); } public CompletableFuture removeMember(UUID uuid) { return CompletableFuture.allOf(storage.getCachingDatabase().delete(this.uuid.toString(), "members-" + uuid), storage.fetchPlayerData(uuid).thenApply(playerData -> playerData.removeClassroom(this.uuid)), getAllMembers().thenApply((members) -> { members.removeIf(data -> data.getUuid().equals(uuid)); return members; }).thenApply((members) -> storage.getCachingDatabase().store(this.uuid.toString(), "members", members))); } public CompletableFuture getMemberData(UUID uuid) { return storage.getCachingDatabase().fetch(this.uuid.toString(), "members-" + uuid).thenApply(o -> { if (!(o instanceof MemberData data)) return null; return data; }); } public CompletableFuture hasMember(UUID uuid) { return getMemberData(uuid).thenApply(Objects::nonNull); } }