mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-15 16:33:02 -03:00
feat: adding new friend session notification
This commit is contained in:
2
proto
2
proto
Submodule proto updated: b8c2db166d...7a23620f93
@@ -370,10 +370,11 @@
|
||||
"restart_to_install_update": "Restart Hydra to install the update",
|
||||
"notification_achievement_unlocked_title": "Achievement unlocked for {{game}}",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} and other {{count}} were unlocked",
|
||||
"new_friend_request_description": "You have received a new friend request",
|
||||
"new_friend_request_description": "{{displayName}} sent you a friend request",
|
||||
"new_friend_request_title": "New friend request",
|
||||
"extraction_complete": "Extraction complete",
|
||||
"game_extracted": "{{title}} extracted successfully"
|
||||
"game_extracted": "{{title}} extracted successfully",
|
||||
"friend_started_playing_game": "{{displayName}} started playing a game"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Open Hydra",
|
||||
|
||||
@@ -371,7 +371,8 @@
|
||||
"notification_achievement_unlocked_title": "Logro desbloqueado de {{game}}",
|
||||
"notification_achievement_unlocked_body": "{{achievement}} y otros {{count}} fueron desbloqueados",
|
||||
"new_friend_request_title": "Nueva solicitud de amistad",
|
||||
"new_friend_request_description": "Has recibido una nueva solicitud de amistad"
|
||||
"new_friend_request_description": "{{displayName}} te envió una solicitud de amistad",
|
||||
"friend_started_playing_game": "{{displayName}} está jugando"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir Hydra",
|
||||
|
||||
@@ -356,9 +356,10 @@
|
||||
"new_update_available": "Versão {{version}} disponível",
|
||||
"restart_to_install_update": "Reinicie o Hydra para instalar a nova versão",
|
||||
"new_friend_request_title": "Novo pedido de amizade",
|
||||
"new_friend_request_description": "Você recebeu um novo pedido de amizade",
|
||||
"new_friend_request_description": "{{displayName}} te enviou um pedido de amizade",
|
||||
"extraction_complete": "Extração concluída",
|
||||
"game_extracted": "{{title}} extraído com sucesso"
|
||||
"game_extracted": "{{title}} extraído com sucesso",
|
||||
"friend_started_playing_game": "{{displayName}} começou a jogar"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir Hydra",
|
||||
|
||||
@@ -341,7 +341,8 @@
|
||||
"new_update_available": "Versão {{version}} disponível",
|
||||
"restart_to_install_update": "Reinicia o Hydra para instalar a nova versão",
|
||||
"new_friend_request_title": "Novo pedido de amizade",
|
||||
"new_friend_request_description": "Recebeste um novo pedido de amizade"
|
||||
"new_friend_request_description": "{{displayName}} te enviou um pedido de amizade",
|
||||
"friend_started_playing_game": "{{displayName}} começou a jogar"
|
||||
},
|
||||
"system_tray": {
|
||||
"open": "Abrir o Hydra",
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import { registerEvent } from "../register-event";
|
||||
import { DownloadManager, HydraApi, gamesPlaytime } from "@main/services";
|
||||
import {
|
||||
DownloadManager,
|
||||
HydraApi,
|
||||
WSClient,
|
||||
gamesPlaytime,
|
||||
} from "@main/services";
|
||||
import { db, downloadsSublevel, gamesSublevel, levelKeys } from "@main/level";
|
||||
|
||||
const signOut = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
@@ -30,6 +35,8 @@ const signOut = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||
databaseOperations,
|
||||
HydraApi.post("/auth/logout").catch(() => {}),
|
||||
]);
|
||||
|
||||
WSClient.close();
|
||||
};
|
||||
|
||||
registerEvent("signOut", signOut);
|
||||
|
||||
@@ -14,348 +14,227 @@ import { MessageType } from "@protobuf-ts/runtime";
|
||||
* @generated from protobuf message FriendRequest
|
||||
*/
|
||||
export interface FriendRequest {
|
||||
/**
|
||||
* @generated from protobuf field: int32 friend_request_count = 1;
|
||||
*/
|
||||
friendRequestCount: number;
|
||||
/**
|
||||
* @generated from protobuf field: optional string sender_id = 2;
|
||||
*/
|
||||
senderId?: string;
|
||||
/**
|
||||
* @generated from protobuf field: int32 friend_request_count = 1;
|
||||
*/
|
||||
friendRequestCount: number;
|
||||
/**
|
||||
* @generated from protobuf field: optional string sender_id = 2;
|
||||
*/
|
||||
senderId?: string;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message UpdateGamePlaytime
|
||||
* @generated from protobuf message FriendGameSession
|
||||
*/
|
||||
export interface UpdateGamePlaytime {
|
||||
/**
|
||||
* @generated from protobuf field: int64 playtime_delta_in_seconds = 1;
|
||||
*/
|
||||
playtimeDeltaInSeconds: bigint;
|
||||
/**
|
||||
* @generated from protobuf field: string last_time_played = 2;
|
||||
*/
|
||||
lastTimePlayed: string;
|
||||
/**
|
||||
* @generated from protobuf field: string game_id = 3;
|
||||
*/
|
||||
gameId: string;
|
||||
export interface FriendGameSession {
|
||||
/**
|
||||
* @generated from protobuf field: string object_id = 1;
|
||||
*/
|
||||
objectId: string;
|
||||
/**
|
||||
* @generated from protobuf field: string shop = 2;
|
||||
*/
|
||||
shop: string;
|
||||
/**
|
||||
* @generated from protobuf field: string friend_id = 3;
|
||||
*/
|
||||
friendId: string;
|
||||
}
|
||||
/**
|
||||
* @generated from protobuf message Envelope
|
||||
*/
|
||||
export interface Envelope {
|
||||
/**
|
||||
* @generated from protobuf oneof: payload
|
||||
*/
|
||||
payload:
|
||||
| {
|
||||
/**
|
||||
* @generated from protobuf oneof: payload
|
||||
*/
|
||||
payload: {
|
||||
oneofKind: "friendRequest";
|
||||
/**
|
||||
* @generated from protobuf field: FriendRequest friend_request = 1;
|
||||
*/
|
||||
friendRequest: FriendRequest;
|
||||
}
|
||||
| {
|
||||
oneofKind: "updateGamePlaytime";
|
||||
} | {
|
||||
oneofKind: "friendGameSession";
|
||||
/**
|
||||
* @generated from protobuf field: UpdateGamePlaytime update_game_playtime = 2;
|
||||
* @generated from protobuf field: FriendGameSession friend_game_session = 2;
|
||||
*/
|
||||
updateGamePlaytime: UpdateGamePlaytime;
|
||||
}
|
||||
| {
|
||||
friendGameSession: FriendGameSession;
|
||||
} | {
|
||||
oneofKind: undefined;
|
||||
};
|
||||
};
|
||||
}
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class FriendRequest$Type extends MessageType<FriendRequest> {
|
||||
constructor() {
|
||||
super("FriendRequest", [
|
||||
{
|
||||
no: 1,
|
||||
name: "friend_request_count",
|
||||
kind: "scalar",
|
||||
T: 5 /*ScalarType.INT32*/,
|
||||
},
|
||||
{
|
||||
no: 2,
|
||||
name: "sender_id",
|
||||
kind: "scalar",
|
||||
opt: true,
|
||||
T: 9 /*ScalarType.STRING*/,
|
||||
},
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<FriendRequest>): FriendRequest {
|
||||
const message = globalThis.Object.create(this.messagePrototype!);
|
||||
message.friendRequestCount = 0;
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<FriendRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(
|
||||
reader: IBinaryReader,
|
||||
length: number,
|
||||
options: BinaryReadOptions,
|
||||
target?: FriendRequest
|
||||
): FriendRequest {
|
||||
const message = target ?? this.create(),
|
||||
end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
const [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int32 friend_request_count */ 1:
|
||||
message.friendRequestCount = reader.int32();
|
||||
break;
|
||||
case /* optional string sender_id */ 2:
|
||||
message.senderId = reader.string();
|
||||
break;
|
||||
default:
|
||||
const u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(
|
||||
`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`
|
||||
);
|
||||
const d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
fieldNo,
|
||||
wireType,
|
||||
d
|
||||
);
|
||||
}
|
||||
constructor() {
|
||||
super("FriendRequest", [
|
||||
{ no: 1, name: "friend_request_count", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
|
||||
{ no: 2, name: "sender_id", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<FriendRequest>): FriendRequest {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
message.friendRequestCount = 0;
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<FriendRequest>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FriendRequest): FriendRequest {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int32 friend_request_count */ 1:
|
||||
message.friendRequestCount = reader.int32();
|
||||
break;
|
||||
case /* optional string sender_id */ 2:
|
||||
message.senderId = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: FriendRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* int32 friend_request_count = 1; */
|
||||
if (message.friendRequestCount !== 0)
|
||||
writer.tag(1, WireType.Varint).int32(message.friendRequestCount);
|
||||
/* optional string sender_id = 2; */
|
||||
if (message.senderId !== undefined)
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.senderId);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(
|
||||
message: FriendRequest,
|
||||
writer: IBinaryWriter,
|
||||
options: BinaryWriteOptions
|
||||
): IBinaryWriter {
|
||||
/* int32 friend_request_count = 1; */
|
||||
if (message.friendRequestCount !== 0)
|
||||
writer.tag(1, WireType.Varint).int32(message.friendRequestCount);
|
||||
/* optional string sender_id = 2; */
|
||||
if (message.senderId !== undefined)
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.senderId);
|
||||
const u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
writer
|
||||
);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message FriendRequest
|
||||
*/
|
||||
export const FriendRequest = new FriendRequest$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class UpdateGamePlaytime$Type extends MessageType<UpdateGamePlaytime> {
|
||||
constructor() {
|
||||
super("UpdateGamePlaytime", [
|
||||
{
|
||||
no: 1,
|
||||
name: "playtime_delta_in_seconds",
|
||||
kind: "scalar",
|
||||
T: 3 /*ScalarType.INT64*/,
|
||||
L: 0 /*LongType.BIGINT*/,
|
||||
},
|
||||
{
|
||||
no: 2,
|
||||
name: "last_time_played",
|
||||
kind: "scalar",
|
||||
T: 9 /*ScalarType.STRING*/,
|
||||
},
|
||||
{ no: 3, name: "game_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<UpdateGamePlaytime>): UpdateGamePlaytime {
|
||||
const message = globalThis.Object.create(this.messagePrototype!);
|
||||
message.playtimeDeltaInSeconds = 0n;
|
||||
message.lastTimePlayed = "";
|
||||
message.gameId = "";
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<UpdateGamePlaytime>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(
|
||||
reader: IBinaryReader,
|
||||
length: number,
|
||||
options: BinaryReadOptions,
|
||||
target?: UpdateGamePlaytime
|
||||
): UpdateGamePlaytime {
|
||||
const message = target ?? this.create(),
|
||||
end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
const [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* int64 playtime_delta_in_seconds */ 1:
|
||||
message.playtimeDeltaInSeconds = reader.int64().toBigInt();
|
||||
break;
|
||||
case /* string last_time_played */ 2:
|
||||
message.lastTimePlayed = reader.string();
|
||||
break;
|
||||
case /* string game_id */ 3:
|
||||
message.gameId = reader.string();
|
||||
break;
|
||||
default:
|
||||
const u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(
|
||||
`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`
|
||||
);
|
||||
const d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
fieldNo,
|
||||
wireType,
|
||||
d
|
||||
);
|
||||
}
|
||||
class FriendGameSession$Type extends MessageType<FriendGameSession> {
|
||||
constructor() {
|
||||
super("FriendGameSession", [
|
||||
{ no: 1, name: "object_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 2, name: "shop", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
|
||||
{ no: 3, name: "friend_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<FriendGameSession>): FriendGameSession {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
message.objectId = "";
|
||||
message.shop = "";
|
||||
message.friendId = "";
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<FriendGameSession>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FriendGameSession): FriendGameSession {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* string object_id */ 1:
|
||||
message.objectId = reader.string();
|
||||
break;
|
||||
case /* string shop */ 2:
|
||||
message.shop = reader.string();
|
||||
break;
|
||||
case /* string friend_id */ 3:
|
||||
message.friendId = reader.string();
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: FriendGameSession, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* string object_id = 1; */
|
||||
if (message.objectId !== "")
|
||||
writer.tag(1, WireType.LengthDelimited).string(message.objectId);
|
||||
/* string shop = 2; */
|
||||
if (message.shop !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.shop);
|
||||
/* string friend_id = 3; */
|
||||
if (message.friendId !== "")
|
||||
writer.tag(3, WireType.LengthDelimited).string(message.friendId);
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(
|
||||
message: UpdateGamePlaytime,
|
||||
writer: IBinaryWriter,
|
||||
options: BinaryWriteOptions
|
||||
): IBinaryWriter {
|
||||
/* int64 playtime_delta_in_seconds = 1; */
|
||||
if (message.playtimeDeltaInSeconds !== 0n)
|
||||
writer.tag(1, WireType.Varint).int64(message.playtimeDeltaInSeconds);
|
||||
/* string last_time_played = 2; */
|
||||
if (message.lastTimePlayed !== "")
|
||||
writer.tag(2, WireType.LengthDelimited).string(message.lastTimePlayed);
|
||||
/* string game_id = 3; */
|
||||
if (message.gameId !== "")
|
||||
writer.tag(3, WireType.LengthDelimited).string(message.gameId);
|
||||
const u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
writer
|
||||
);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message UpdateGamePlaytime
|
||||
* @generated MessageType for protobuf message FriendGameSession
|
||||
*/
|
||||
export const UpdateGamePlaytime = new UpdateGamePlaytime$Type();
|
||||
export const FriendGameSession = new FriendGameSession$Type();
|
||||
// @generated message type with reflection information, may provide speed optimized methods
|
||||
class Envelope$Type extends MessageType<Envelope> {
|
||||
constructor() {
|
||||
super("Envelope", [
|
||||
{
|
||||
no: 1,
|
||||
name: "friend_request",
|
||||
kind: "message",
|
||||
oneof: "payload",
|
||||
T: () => FriendRequest,
|
||||
},
|
||||
{
|
||||
no: 2,
|
||||
name: "update_game_playtime",
|
||||
kind: "message",
|
||||
oneof: "payload",
|
||||
T: () => UpdateGamePlaytime,
|
||||
},
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Envelope>): Envelope {
|
||||
const message = globalThis.Object.create(this.messagePrototype!);
|
||||
message.payload = { oneofKind: undefined };
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Envelope>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(
|
||||
reader: IBinaryReader,
|
||||
length: number,
|
||||
options: BinaryReadOptions,
|
||||
target?: Envelope
|
||||
): Envelope {
|
||||
const message = target ?? this.create(),
|
||||
end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
const [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* FriendRequest friend_request */ 1:
|
||||
message.payload = {
|
||||
oneofKind: "friendRequest",
|
||||
friendRequest: FriendRequest.internalBinaryRead(
|
||||
reader,
|
||||
reader.uint32(),
|
||||
options,
|
||||
(message.payload as any).friendRequest
|
||||
),
|
||||
};
|
||||
break;
|
||||
case /* UpdateGamePlaytime update_game_playtime */ 2:
|
||||
message.payload = {
|
||||
oneofKind: "updateGamePlaytime",
|
||||
updateGamePlaytime: UpdateGamePlaytime.internalBinaryRead(
|
||||
reader,
|
||||
reader.uint32(),
|
||||
options,
|
||||
(message.payload as any).updateGamePlaytime
|
||||
),
|
||||
};
|
||||
break;
|
||||
default:
|
||||
const u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(
|
||||
`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`
|
||||
);
|
||||
const d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
fieldNo,
|
||||
wireType,
|
||||
d
|
||||
);
|
||||
}
|
||||
constructor() {
|
||||
super("Envelope", [
|
||||
{ no: 1, name: "friend_request", kind: "message", oneof: "payload", T: () => FriendRequest },
|
||||
{ no: 2, name: "friend_game_session", kind: "message", oneof: "payload", T: () => FriendGameSession }
|
||||
]);
|
||||
}
|
||||
create(value?: PartialMessage<Envelope>): Envelope {
|
||||
const message = globalThis.Object.create((this.messagePrototype!));
|
||||
message.payload = { oneofKind: undefined };
|
||||
if (value !== undefined)
|
||||
reflectionMergePartial<Envelope>(this, message, value);
|
||||
return message;
|
||||
}
|
||||
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Envelope): Envelope {
|
||||
let message = target ?? this.create(), end = reader.pos + length;
|
||||
while (reader.pos < end) {
|
||||
let [fieldNo, wireType] = reader.tag();
|
||||
switch (fieldNo) {
|
||||
case /* FriendRequest friend_request */ 1:
|
||||
message.payload = {
|
||||
oneofKind: "friendRequest",
|
||||
friendRequest: FriendRequest.internalBinaryRead(reader, reader.uint32(), options, (message.payload as any).friendRequest)
|
||||
};
|
||||
break;
|
||||
case /* FriendGameSession friend_game_session */ 2:
|
||||
message.payload = {
|
||||
oneofKind: "friendGameSession",
|
||||
friendGameSession: FriendGameSession.internalBinaryRead(reader, reader.uint32(), options, (message.payload as any).friendGameSession)
|
||||
};
|
||||
break;
|
||||
default:
|
||||
let u = options.readUnknownField;
|
||||
if (u === "throw")
|
||||
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
|
||||
let d = reader.skip(wireType);
|
||||
if (u !== false)
|
||||
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(message: Envelope, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
|
||||
/* FriendRequest friend_request = 1; */
|
||||
if (message.payload.oneofKind === "friendRequest")
|
||||
FriendRequest.internalBinaryWrite(message.payload.friendRequest, writer.tag(1, WireType.LengthDelimited).fork(), options).join();
|
||||
/* FriendGameSession friend_game_session = 2; */
|
||||
if (message.payload.oneofKind === "friendGameSession")
|
||||
FriendGameSession.internalBinaryWrite(message.payload.friendGameSession, writer.tag(2, WireType.LengthDelimited).fork(), options).join();
|
||||
let u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
|
||||
return writer;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
internalBinaryWrite(
|
||||
message: Envelope,
|
||||
writer: IBinaryWriter,
|
||||
options: BinaryWriteOptions
|
||||
): IBinaryWriter {
|
||||
/* FriendRequest friend_request = 1; */
|
||||
if (message.payload.oneofKind === "friendRequest")
|
||||
FriendRequest.internalBinaryWrite(
|
||||
message.payload.friendRequest,
|
||||
writer.tag(1, WireType.LengthDelimited).fork(),
|
||||
options
|
||||
).join();
|
||||
/* UpdateGamePlaytime update_game_playtime = 2; */
|
||||
if (message.payload.oneofKind === "updateGamePlaytime")
|
||||
UpdateGamePlaytime.internalBinaryWrite(
|
||||
message.payload.updateGamePlaytime,
|
||||
writer.tag(2, WireType.LengthDelimited).fork(),
|
||||
options
|
||||
).join();
|
||||
const u = options.writeUnknownFields;
|
||||
if (u !== false)
|
||||
(u == true ? UnknownFieldHandler.onWrite : u)(
|
||||
this.typeName,
|
||||
message,
|
||||
writer
|
||||
);
|
||||
return writer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @generated MessageType for protobuf message Envelope
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { Aria2, DownloadManager, Ludusavi, startMainLoop } from "./services";
|
||||
import { RealDebridClient } from "./services/download/real-debrid";
|
||||
import { HydraApi } from "./services/hydra-api";
|
||||
import { uploadGamesBatch } from "./services/library-sync";
|
||||
import { downloadsSublevel } from "./level/sublevels/downloads";
|
||||
import { sortBy } from "lodash-es";
|
||||
import { Downloader } from "@shared";
|
||||
import { levelKeys, db } from "./level";
|
||||
import type { UserPreferences } from "@types";
|
||||
import { TorBoxClient } from "./services/download/torbox";
|
||||
import { CommonRedistManager } from "./services/common-redist-manager";
|
||||
import { WSManager } from "./services/ws-manager";
|
||||
import { SystemPath } from "./services/system-path";
|
||||
import {
|
||||
WSClient,
|
||||
SystemPath,
|
||||
CommonRedistManager,
|
||||
TorBoxClient,
|
||||
RealDebridClient,
|
||||
Aria2,
|
||||
DownloadManager,
|
||||
Ludusavi,
|
||||
HydraApi,
|
||||
uploadGamesBatch,
|
||||
startMainLoop,
|
||||
} from "@main/services";
|
||||
|
||||
export const loadState = async () => {
|
||||
SystemPath.checkIfPathsAreAvailable();
|
||||
@@ -38,7 +43,7 @@ export const loadState = async () => {
|
||||
|
||||
await HydraApi.setupApi().then(() => {
|
||||
uploadGamesBatch();
|
||||
WSManager.connect();
|
||||
WSClient.connect();
|
||||
});
|
||||
|
||||
const downloads = await downloadsSublevel
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from "./download-manager";
|
||||
export * from "./real-debrid";
|
||||
export * from "./torbox";
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getUserData } from "./user/get-user-data";
|
||||
import { db } from "@main/level";
|
||||
import { levelKeys } from "@main/level/sublevels";
|
||||
import type { Auth, User } from "@types";
|
||||
import { WSManager } from "./ws-manager";
|
||||
import { WSClient } from "./ws/ws-client";
|
||||
|
||||
interface HydraApiOptions {
|
||||
needsAuth?: boolean;
|
||||
@@ -102,8 +102,8 @@ export class HydraApi {
|
||||
WindowManager.mainWindow.webContents.send("on-signin");
|
||||
await clearGamesRemoteIds();
|
||||
uploadGamesBatch();
|
||||
WSManager.close();
|
||||
WSManager.connect();
|
||||
WSClient.close();
|
||||
WSClient.connect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,3 +12,6 @@ export * from "./7zip";
|
||||
export * from "./game-files-manager";
|
||||
export * from "./common-redist-manager";
|
||||
export * from "./aria2";
|
||||
export * from "./ws";
|
||||
export * from "./system-path";
|
||||
export * from "./library-sync";
|
||||
|
||||
@@ -10,7 +10,7 @@ import icon from "@resources/icon.png?asset";
|
||||
import { NotificationOptions, toXmlString } from "./xml";
|
||||
import { logger } from "../logger";
|
||||
import { WindowManager } from "../window-manager";
|
||||
import type { Game, UserPreferences } from "@types";
|
||||
import type { Game, GameStats, UserPreferences, UserProfile } from "@types";
|
||||
import { db, levelKeys } from "@main/level";
|
||||
import { restartAndInstallUpdate } from "@main/events/autoupdater/restart-and-install-update";
|
||||
import { SystemPath } from "../system-path";
|
||||
@@ -82,7 +82,7 @@ export const publishNotificationUpdateReadyToInstall = async (
|
||||
};
|
||||
|
||||
export const publishNewFriendRequestNotification = async (
|
||||
senderProfileImageUrl?: string
|
||||
user: UserProfile
|
||||
) => {
|
||||
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||
levelKeys.userPreferences,
|
||||
@@ -99,9 +99,26 @@ export const publishNewFriendRequestNotification = async (
|
||||
}),
|
||||
body: t("new_friend_request_description", {
|
||||
ns: "notifications",
|
||||
displayName: user.displayName,
|
||||
}),
|
||||
icon: senderProfileImageUrl
|
||||
? await downloadImage(senderProfileImageUrl)
|
||||
icon: user?.profileImageUrl
|
||||
? await downloadImage(user.profileImageUrl)
|
||||
: trayIcon,
|
||||
}).show();
|
||||
};
|
||||
|
||||
export const publishFriendStartedPlayingGameNotification = async (
|
||||
friend: UserProfile,
|
||||
game: GameStats
|
||||
) => {
|
||||
new Notification({
|
||||
title: t("friend_started_playing_game", {
|
||||
ns: "notifications",
|
||||
displayName: friend.displayName,
|
||||
}),
|
||||
body: game.assets?.title,
|
||||
icon: friend?.profileImageUrl
|
||||
? await downloadImage(friend.profileImageUrl)
|
||||
: trayIcon,
|
||||
}).show();
|
||||
};
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import { WebSocket } from "ws";
|
||||
import { HydraApi } from "./hydra-api";
|
||||
import { Envelope } from "@main/generated/envelope";
|
||||
import { logger } from "./logger";
|
||||
import { WindowManager } from "./window-manager";
|
||||
|
||||
export class WSManager {
|
||||
private static ws: WebSocket | null = null;
|
||||
private static reconnectInterval = 1000;
|
||||
private static maxReconnectInterval = 30000;
|
||||
private static reconnectAttempts = 0;
|
||||
private static reconnecting = false;
|
||||
|
||||
static async connect() {
|
||||
const { token } = await HydraApi.post<{ token: string }>("/auth/ws");
|
||||
|
||||
this.ws = new WebSocket(import.meta.env.MAIN_VITE_WS_URL, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
});
|
||||
|
||||
this.ws.on("open", () => {
|
||||
logger.info("WS connected");
|
||||
this.reconnectInterval = 1000;
|
||||
this.reconnecting = false;
|
||||
});
|
||||
|
||||
this.ws.on("message", (message) => {
|
||||
const envelope = Envelope.fromBinary(
|
||||
new Uint8Array(Buffer.from(message.toString()))
|
||||
);
|
||||
|
||||
if (envelope.payload.oneofKind === "friendRequest") {
|
||||
WindowManager.mainWindow?.webContents.send("on-sync-friend-requests", {
|
||||
friendRequestCount: envelope.payload.friendRequest.friendRequestCount,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.ws.on("close", () => {
|
||||
logger.warn("WS closed. Attempting reconnect...");
|
||||
this.tryReconnect();
|
||||
});
|
||||
|
||||
this.ws.on("error", (err) => {
|
||||
logger.error("WS error:", err);
|
||||
this.tryReconnect();
|
||||
});
|
||||
}
|
||||
|
||||
private static async tryReconnect() {
|
||||
if (this.reconnecting) return;
|
||||
|
||||
this.reconnecting = true;
|
||||
this.reconnectAttempts++;
|
||||
|
||||
const waitTime = Math.min(
|
||||
this.reconnectInterval * 2 ** this.reconnectAttempts,
|
||||
this.maxReconnectInterval
|
||||
);
|
||||
logger.info(`Reconnecting in ${waitTime / 1000}s...`);
|
||||
|
||||
setTimeout(() => {
|
||||
this.connect();
|
||||
}, waitTime);
|
||||
}
|
||||
|
||||
public static async close() {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,21 @@
|
||||
border-right: 1px solid globals.$border-color;
|
||||
}
|
||||
|
||||
&__cover-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: globals.$body-color;
|
||||
width: 200px;
|
||||
height: 103px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
rgba(255, 255, 255, 0.1) 0%,
|
||||
rgba(255, 255, 255, 0.05) 50%,
|
||||
rgba(255, 255, 255, 0.1) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&__details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useNavigate } from "react-router-dom";
|
||||
import "./game-item.scss";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { CatalogueSearchResult } from "@types";
|
||||
import { QuestionIcon } from "@primer/octicons-react";
|
||||
|
||||
export interface GameItemProps {
|
||||
game: CatalogueSearchResult;
|
||||
@@ -43,18 +44,32 @@ export function GameItem({ game }: GameItemProps) {
|
||||
});
|
||||
}, [game.genres, language, steamGenres]);
|
||||
|
||||
const libraryImage = useMemo(() => {
|
||||
if (game.libraryImageUrl) {
|
||||
return (
|
||||
<img
|
||||
className="game-item__cover"
|
||||
src={game.libraryImageUrl}
|
||||
alt={game.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="game-item__cover-placeholder">
|
||||
<QuestionIcon size={28} />
|
||||
</div>
|
||||
);
|
||||
}, [game.libraryImageUrl, game.title]);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="game-item"
|
||||
onClick={() => navigate(buildGameDetailsPath(game))}
|
||||
>
|
||||
<img
|
||||
className="game-item__cover"
|
||||
src={game.libraryImageUrl}
|
||||
alt={game.title}
|
||||
loading="lazy"
|
||||
/>
|
||||
{libraryImage}
|
||||
|
||||
<div className="game-item__details">
|
||||
<span>{game.title}</span>
|
||||
|
||||
Reference in New Issue
Block a user