mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-22 13:02:38 +02:00
web: Added WebSession support.
This commit is contained in:
parent
6620dfaa6f
commit
e2db987144
@ -9,6 +9,7 @@
|
|||||||
#include "../services/applet.h"
|
#include "../services/applet.h"
|
||||||
#include "../services/caps.h"
|
#include "../services/caps.h"
|
||||||
#include "../services/acc.h"
|
#include "../services/acc.h"
|
||||||
|
#include "../kernel/mutex.h"
|
||||||
|
|
||||||
/// This indicates the type of web-applet.
|
/// This indicates the type of web-applet.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -43,6 +44,26 @@ typedef enum {
|
|||||||
WebFooterButtonId_Max, ///< Values starting with this are invalid.
|
WebFooterButtonId_Max, ///< Values starting with this are invalid.
|
||||||
} WebFooterButtonId;
|
} WebFooterButtonId;
|
||||||
|
|
||||||
|
/// WebSessionBootMode
|
||||||
|
typedef enum {
|
||||||
|
WebSessionBootMode_AllForeground = 0, ///< AllForeground. This is the default.
|
||||||
|
WebSessionBootMode_AllForegroundInitiallyHidden = 1, ///< AllForegroundInitiallyHidden
|
||||||
|
} WebSessionBootMode;
|
||||||
|
|
||||||
|
/// WebSessionSendMessageKind
|
||||||
|
typedef enum {
|
||||||
|
WebSessionSendMessageKind_BrowserEngineContent = 0x0, ///< BrowserEngine Content
|
||||||
|
WebSessionSendMessageKind_SystemMessageAppear = 0x100, ///< SystemMessage Appear
|
||||||
|
WebSessionSendMessageKind_Ack = 0x1000, ///< Ack
|
||||||
|
} WebSessionSendMessageKind;
|
||||||
|
|
||||||
|
/// WebSessionReceiveMessageKind
|
||||||
|
typedef enum {
|
||||||
|
WebSessionReceiveMessageKind_BrowserEngineContent = 0x0, ///< BrowserEngine Content
|
||||||
|
WebSessionReceiveMessageKind_AckBrowserEngine = 0x1000, ///< Ack BrowserEngine
|
||||||
|
WebSessionReceiveMessageKind_AckSystemMessage = 0x1001, ///< Ack SystemMessage
|
||||||
|
} WebSessionReceiveMessageKind;
|
||||||
|
|
||||||
/// Struct for the WebWifi applet input storage.
|
/// Struct for the WebWifi applet input storage.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 unk_x0; ///< Official sw sets this to 0 with appletStorageWrite, separately from the rest of the config struct.
|
u32 unk_x0; ///< Official sw sets this to 0 with appletStorageWrite, separately from the rest of the config struct.
|
||||||
@ -114,6 +135,33 @@ typedef struct {
|
|||||||
u8 unk_x7;
|
u8 unk_x7;
|
||||||
} PACKED WebBootFooterButtonEntry;
|
} PACKED WebBootFooterButtonEntry;
|
||||||
|
|
||||||
|
/// StorageHandleQueue
|
||||||
|
typedef struct {
|
||||||
|
s32 read_pos;
|
||||||
|
s32 write_pos;
|
||||||
|
s32 max_storages;
|
||||||
|
bool is_full;
|
||||||
|
AppletStorage storages[0x10];
|
||||||
|
} WebSessionStorageHandleQueue;
|
||||||
|
|
||||||
|
/// WebSession
|
||||||
|
typedef struct {
|
||||||
|
Mutex mutex;
|
||||||
|
WebCommonConfig *config;
|
||||||
|
struct {
|
||||||
|
u32 count;
|
||||||
|
u32 cur_size;
|
||||||
|
} queue[2];
|
||||||
|
WebSessionStorageHandleQueue storage_queue;
|
||||||
|
} WebSession;
|
||||||
|
|
||||||
|
/// SessionMessageHeader
|
||||||
|
typedef struct {
|
||||||
|
u32 kind; ///< Message Kind (\ref WebSessionSendMessageKind / \ref WebSessionReceiveMessageKind)
|
||||||
|
u32 size; ///< Data size following the header.
|
||||||
|
u8 reserved[0x8]; ///< Unused
|
||||||
|
} WebSessionMessageHeader;
|
||||||
|
|
||||||
/// Types for \ref WebArgTLV, input storage.
|
/// Types for \ref WebArgTLV, input storage.
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WebArgType_Url = 0x1, ///< [1.0.0+] String, size 0xC00. Initial URL.
|
WebArgType_Url = 0x1, ///< [1.0.0+] String, size 0xC00. Initial URL.
|
||||||
@ -176,7 +224,7 @@ typedef enum {
|
|||||||
WebArgType_BootFooterButton = 0x3E, ///< [6.0.0+] Array of \ref WebBootFooterButtonEntry with 0x10 entries.
|
WebArgType_BootFooterButton = 0x3E, ///< [6.0.0+] Array of \ref WebBootFooterButtonEntry with 0x10 entries.
|
||||||
WebArgType_OverrideWebAudioVolume = 0x3F, ///< [6.0.0+] float
|
WebArgType_OverrideWebAudioVolume = 0x3F, ///< [6.0.0+] float
|
||||||
WebArgType_OverrideMediaAudioVolume = 0x40, ///< [6.0.0+] float
|
WebArgType_OverrideMediaAudioVolume = 0x40, ///< [6.0.0+] float
|
||||||
WebArgType_SessionBootMode = 0x41, ///< [7.0.0+] u32 enum WebSessionBootMode
|
WebArgType_SessionBootMode = 0x41, ///< [7.0.0+] u32 enum \ref WebSessionBootMode
|
||||||
WebArgType_SessionFlag = 0x42, ///< [7.0.0+] u8 bool, enables using WebSession when set.
|
WebArgType_SessionFlag = 0x42, ///< [7.0.0+] u8 bool, enables using WebSession when set.
|
||||||
WebArgType_MediaPlayerUi = 0x43, ///< [8.0.0+] u8 bool
|
WebArgType_MediaPlayerUi = 0x43, ///< [8.0.0+] u8 bool
|
||||||
} WebArgType;
|
} WebArgType;
|
||||||
@ -649,6 +697,14 @@ Result webConfigSetOverrideWebAudioVolume(WebCommonConfig* config, float value);
|
|||||||
*/
|
*/
|
||||||
Result webConfigSetOverrideMediaAudioVolume(WebCommonConfig* config, float value);
|
Result webConfigSetOverrideMediaAudioVolume(WebCommonConfig* config, float value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets \ref WebSessionBootMode.
|
||||||
|
* @note Only available with config created by \ref webOfflineCreate or \ref webPageCreate, on [7.0.0+].
|
||||||
|
* @param config WebCommonConfig object.
|
||||||
|
* @param mode \ref WebSessionBootMode
|
||||||
|
*/
|
||||||
|
Result webConfigSetBootMode(WebCommonConfig* config, WebSessionBootMode mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets whether MediaPlayerUi is enabled.
|
* @brief Sets whether MediaPlayerUi is enabled.
|
||||||
* @note Only available with config created by \ref webOfflineCreate on [8.0.0+].
|
* @note Only available with config created by \ref webOfflineCreate on [8.0.0+].
|
||||||
@ -726,3 +782,72 @@ Result webReplyGetPostId(WebCommonReply *reply, char *outstr, size_t outstr_maxs
|
|||||||
*/
|
*/
|
||||||
Result webReplyGetMediaPlayerAutoClosedByCompletion(WebCommonReply *reply, bool *flag);
|
Result webReplyGetMediaPlayerAutoClosedByCompletion(WebCommonReply *reply, bool *flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a \ref WebSession object.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param config WebCommonConfig object.
|
||||||
|
*/
|
||||||
|
void webSessionCreate(WebSession *s, WebCommonConfig* config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes a \ref WebSession object.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
*/
|
||||||
|
void webSessionClose(WebSession *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Launches the applet for \ref WebSession.
|
||||||
|
* @note Only available with config created by \ref webOfflineCreate or \ref webPageCreate, on [7.0.0+].
|
||||||
|
* @note Do not use \ref webConfigShow when using WebSession.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param[out] out_event Output Event with autoclear=false, from \ref appletHolderGetExitEvent. Optional, can be NULL.
|
||||||
|
*/
|
||||||
|
Result webSessionStart(WebSession *s, Event **out_event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Waits for the applet to exit.
|
||||||
|
* @note This must be used before \ref webSessionClose, when \ref webSessionStart was used successfully.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param out Optional output applet reply data, can be NULL.
|
||||||
|
*/
|
||||||
|
Result webSessionWaitForExit(WebSession *s, WebCommonReply *out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request the applet to exit.
|
||||||
|
* @note Use this instead of \ref webConfigRequestExit, when using WebSession.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
*/
|
||||||
|
Result webSessionRequestExit(WebSession *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Request the applet to Appear, this is only needed with ::WebSessionBootMode_AllForegroundInitiallyHidden.
|
||||||
|
* @note This should not be used before \ref webSessionStart.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param[out] flag Whether the message was sent successfully.
|
||||||
|
*/
|
||||||
|
Result webSessionAppear(WebSession *s, bool *flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TrySendContentMessage
|
||||||
|
* @note This should not be used before \ref webSessionStart.
|
||||||
|
* @note The JS-side for this is only available when JsExtension is enabled via \ref webConfigSetJsExtension.
|
||||||
|
* @note The JS-side may ignore this if it's sent too soon after the applet launches.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param[in] content Input content NUL-terminated string.
|
||||||
|
* @param[in] size Size of content.
|
||||||
|
* @param[out] flag Whether the message was sent successfully.
|
||||||
|
*/
|
||||||
|
Result webSessionTrySendContentMessage(WebSession *s, const char *content, u32 size, bool *flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief TryReceiveContentMessage
|
||||||
|
* @note This should not be used before \ref webSessionStart.
|
||||||
|
* @note The JS-side for this is only available when JsExtension is enabled via \ref webConfigSetJsExtension.
|
||||||
|
* @param s \ref WebSession
|
||||||
|
* @param[out] content Output content string, always NUL-terminated.
|
||||||
|
* @param[in] size Max size of content.
|
||||||
|
* @param[out] out_size Original content size, prior to being clamped to the specified size param.
|
||||||
|
* @param[out] flag Whether the message was received successfully.
|
||||||
|
*/
|
||||||
|
Result webSessionTryReceiveContentMessage(WebSession *s, char *content, u64 size, u64 *out_size, bool *flag);
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#include "applets/web.h"
|
#include "applets/web.h"
|
||||||
#include "runtime/hosversion.h"
|
#include "runtime/hosversion.h"
|
||||||
|
|
||||||
static Result _webLaunch(AppletHolder* holder, AppletId id, u32 version, void* arg, size_t arg_size) {
|
static Result _webLaunch(AppletHolder* holder, AppletId id, LibAppletMode mode, u32 version, void* arg, size_t arg_size) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
|
|
||||||
rc = appletCreateLibraryApplet(holder, id, LibAppletMode_AllForeground);
|
rc = appletCreateLibraryApplet(holder, id, mode);
|
||||||
if (R_FAILED(rc)) return rc;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
LibAppletArgs commonargs;
|
LibAppletArgs commonargs;
|
||||||
@ -43,7 +43,7 @@ static Result _webHandleExit(AppletHolder* holder, void* reply_buffer, size_t re
|
|||||||
static Result _webShow(AppletHolder *holder, AppletId id, u32 version, void* arg, size_t arg_size, void* reply_buffer, size_t reply_size) {
|
static Result _webShow(AppletHolder *holder, AppletId id, u32 version, void* arg, size_t arg_size, void* reply_buffer, size_t reply_size) {
|
||||||
Result rc = 0;
|
Result rc = 0;
|
||||||
|
|
||||||
rc = _webLaunch(holder, id, version, arg, arg_size);
|
rc = _webLaunch(holder, id, LibAppletMode_AllForeground, version, arg, arg_size);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) rc = _webHandleExit(holder, reply_buffer, reply_size);
|
if (R_SUCCEEDED(rc)) rc = _webHandleExit(holder, reply_buffer, reply_size);
|
||||||
|
|
||||||
@ -264,6 +264,10 @@ static Result _webConfigGetFlag(WebCommonConfig* config, u16 type, bool *arg) {
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Result _webConfigGetU32(WebCommonConfig* config, u16 type, u32 *arg) {
|
||||||
|
return _webConfigGet(config, type, arg, sizeof(*arg));
|
||||||
|
}
|
||||||
|
|
||||||
Result webPageCreate(WebCommonConfig* config, const char* url) {
|
Result webPageCreate(WebCommonConfig* config, const char* url) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
_webArgInitialize(config, AppletId_web, WebShimKind_Web);
|
_webArgInitialize(config, AppletId_web, WebShimKind_Web);
|
||||||
@ -685,39 +689,51 @@ Result webConfigSetOverrideMediaAudioVolume(WebCommonConfig* config, float value
|
|||||||
return _webConfigSetFloat(config, WebArgType_OverrideMediaAudioVolume, value);
|
return _webConfigSetFloat(config, WebArgType_OverrideMediaAudioVolume, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result webConfigSetBootMode(WebCommonConfig* config, WebSessionBootMode mode) {
|
||||||
|
WebShimKind shim = _webGetShimKind(config);
|
||||||
|
if (shim != WebShimKind_Offline && shim != WebShimKind_Web) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
return _webConfigSetU32(config, WebArgType_SessionBootMode, mode);
|
||||||
|
}
|
||||||
|
|
||||||
Result webConfigSetMediaPlayerUi(WebCommonConfig* config, bool flag) {
|
Result webConfigSetMediaPlayerUi(WebCommonConfig* config, bool flag) {
|
||||||
if (_webGetShimKind(config) != WebShimKind_Offline) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
if (_webGetShimKind(config) != WebShimKind_Offline) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
if (hosversionBefore(8,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
if (hosversionBefore(8,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
return _webConfigSetFlag(config, WebArgType_MediaPlayerUi, flag);
|
return _webConfigSetFlag(config, WebArgType_MediaPlayerUi, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _webConfigInitReply(WebCommonConfig* config, WebCommonReply *out, void** reply, size_t *reply_size) {
|
||||||
|
if (out) {
|
||||||
|
// ShareApplet on [3.0.0+] uses TLV storage for the reply, while older versions + everything else uses *ReturnValue.
|
||||||
|
// Web also uses TLV storage for the reply on [8.0.0+].
|
||||||
|
WebShimKind shimKind = _webGetShimKind(config);
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
out->shimKind = shimKind;
|
||||||
|
|
||||||
|
if (config->version >= 0x30000 && shimKind == WebShimKind_Share) out->type = true;
|
||||||
|
if (config->version >= 0x80000 && shimKind == WebShimKind_Web) out->type = true;
|
||||||
|
|
||||||
|
if (!out->type) {
|
||||||
|
*reply = &out->ret;
|
||||||
|
*reply_size = sizeof(out->ret);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*reply = &out->storage;
|
||||||
|
*reply_size = sizeof(out->storage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Result webConfigShow(WebCommonConfig* config, WebCommonReply *out) {
|
Result webConfigShow(WebCommonConfig* config, WebCommonReply *out) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
void* reply = NULL;
|
void* reply = NULL;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
WebShimKind shimKind = _webGetShimKind(config);
|
WebShimKind shimKind = _webGetShimKind(config);
|
||||||
|
|
||||||
if (out) {
|
_webConfigInitReply(config, out, &reply, &size);
|
||||||
// ShareApplet on [3.0.0+] uses TLV storage for the reply, while older versions + everything else uses *ReturnValue.
|
|
||||||
// Web also uses TLV storage for the reply on [8.0.0+].
|
|
||||||
memset(out, 0, sizeof(*out));
|
|
||||||
out->shimKind = shimKind;
|
|
||||||
|
|
||||||
if (config->version >= 0x30000 && shimKind == WebShimKind_Share) out->type = true;
|
|
||||||
if (config->version >= 0x80000 && shimKind == WebShimKind_Web) out->type = true;
|
|
||||||
|
|
||||||
if (!out->type) {
|
|
||||||
reply = &out->ret;
|
|
||||||
size = sizeof(out->ret);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reply = &out->storage;
|
|
||||||
size = sizeof(out->storage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = _webShow(&config->holder, config->appletid, config->version, &config->arg, sizeof(config->arg), reply, size);
|
rc = _webShow(&config->holder, config->appletid, config->version, &config->arg, sizeof(config->arg), reply, size);
|
||||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(10,0,0) && (shimKind == WebShimKind_Web || shimKind == WebShimKind_Offline)) {
|
if (R_SUCCEEDED(rc) && hosversionAtLeast(10,0,0) && out && (shimKind == WebShimKind_Web || shimKind == WebShimKind_Offline)) {
|
||||||
WebExitReason reason;
|
WebExitReason reason;
|
||||||
rc = webReplyGetExitReason(out, &reason);
|
rc = webReplyGetExitReason(out, &reason);
|
||||||
if (R_SUCCEEDED(rc) && reason == WebExitReason_UnknownE) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
if (R_SUCCEEDED(rc) && reason == WebExitReason_UnknownE) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
||||||
@ -807,3 +823,295 @@ Result webReplyGetMediaPlayerAutoClosedByCompletion(WebCommonReply *reply, bool
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s32 _webSessionStorageHandleQueueGetCount(WebSessionStorageHandleQueue *s) {
|
||||||
|
if (s->is_full) return s->max_storages;
|
||||||
|
return (s->write_pos + s->max_storages - s->read_pos) % s->max_storages;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppletStorage *_webSessionStorageAt(WebSessionStorageHandleQueue *s, s32 pos) {
|
||||||
|
return &s->storages[(s->read_pos + pos) % s->max_storages];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _webSessionStorageHandleQueueCreate(WebSessionStorageHandleQueue *s) {
|
||||||
|
memset(s, 0, sizeof(*s));
|
||||||
|
s->max_storages = 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _webSessionStorageHandleQueueClear(WebSessionStorageHandleQueue *s) {
|
||||||
|
while (_webSessionStorageHandleQueueGetCount(s) >= 1) {
|
||||||
|
s->is_full = false;
|
||||||
|
appletStorageClose(_webSessionStorageAt(s, 0));
|
||||||
|
s->read_pos = (s->read_pos + 1) % s->max_storages;
|
||||||
|
}
|
||||||
|
s->read_pos = 0;
|
||||||
|
s->write_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _webSessionStorageEnqueue(WebSessionStorageHandleQueue *s, AppletStorage *storage) {
|
||||||
|
s->write_pos = (s->write_pos + 1) % s->max_storages;
|
||||||
|
s->is_full = s->read_pos==s->write_pos;
|
||||||
|
AppletStorage *storageptr = _webSessionStorageAt(s, _webSessionStorageHandleQueueGetCount(s)-1);
|
||||||
|
appletStorageClose(storageptr); // sdknso doesn't do this - we will though, since otherwise the overwritten storage will not get closed, when the storage queue is full.
|
||||||
|
*storageptr = *storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AppletStorage *_webSessionStorageDequeue(WebSessionStorageHandleQueue *s) {
|
||||||
|
s->is_full = false;
|
||||||
|
AppletStorage *storage = _webSessionStorageAt(s, 0);
|
||||||
|
s->read_pos = (s->read_pos+1) % s->max_storages;
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSessionCreate(WebSession *s, WebCommonConfig* config) {
|
||||||
|
mutexInit(&s->mutex);
|
||||||
|
memset(s->queue, 0, sizeof(s->queue));
|
||||||
|
s->config = config;
|
||||||
|
_webSessionStorageHandleQueueCreate(&s->storage_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void webSessionClose(WebSession *s) {
|
||||||
|
_webSessionStorageHandleQueueClear(&s->storage_queue);
|
||||||
|
s->config = NULL;
|
||||||
|
memset(s->queue, 0, sizeof(s->queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionStart(WebSession *s, Event **out_event) {
|
||||||
|
Result rc=0;
|
||||||
|
WebShimKind shim = _webGetShimKind(s->config);
|
||||||
|
|
||||||
|
if (shim != WebShimKind_Offline && shim != WebShimKind_Web) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
||||||
|
if (hosversionBefore(7,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
|
||||||
|
|
||||||
|
u32 tmp=0;
|
||||||
|
_webConfigGetU32(s->config, WebArgType_SessionBootMode, &tmp);
|
||||||
|
LibAppletMode mode = tmp == WebSessionBootMode_AllForegroundInitiallyHidden ? LibAppletMode_AllForegroundInitiallyHidden : LibAppletMode_AllForeground;
|
||||||
|
|
||||||
|
rc = _webConfigSetFlag(s->config, WebArgType_SessionFlag, true);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = _webLaunch(&s->config->holder, s->config->appletid, mode, s->config->version, &s->config->arg, sizeof(s->config->arg));
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && out_event) *out_event = appletHolderGetExitEvent(&s->config->holder);
|
||||||
|
|
||||||
|
if (R_FAILED(rc)) appletHolderClose(&s->config->holder);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionWaitForExit(WebSession *s, WebCommonReply *out) {
|
||||||
|
Result rc=0;
|
||||||
|
void* reply = NULL;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
_webConfigInitReply(s->config, out, &reply, &size);
|
||||||
|
|
||||||
|
rc = _webHandleExit(&s->config->holder, reply, size);
|
||||||
|
appletHolderClose(&s->config->holder);
|
||||||
|
_webSessionStorageHandleQueueClear(&s->storage_queue);
|
||||||
|
if (R_SUCCEEDED(rc) && hosversionAtLeast(10,0,0) && out) {
|
||||||
|
WebExitReason reason;
|
||||||
|
rc = webReplyGetExitReason(out, &reason);
|
||||||
|
if (R_SUCCEEDED(rc) && reason == WebExitReason_UnknownE) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionRequestExit(WebSession *s) {
|
||||||
|
mutexLock(&s->mutex);
|
||||||
|
Result rc = appletHolderRequestExit(&s->config->holder);
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _webSessionReceiveStorageHandles(WebSession *s) {
|
||||||
|
Result rc=0;
|
||||||
|
AppletStorage storage;
|
||||||
|
Event *event = NULL;
|
||||||
|
WebSessionMessageHeader tmphdr={0};
|
||||||
|
u8 data[0x20]={0};
|
||||||
|
WebSessionMessageHeader *datahdr = (WebSessionMessageHeader*)data;
|
||||||
|
|
||||||
|
rc = appletHolderGetPopInteractiveOutDataEvent(&s->config->holder, &event);
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
|
while (appletHolderActive(&s->config->holder)) {
|
||||||
|
if (appletHolderCheckFinished(&s->config->holder)) return 0;
|
||||||
|
if (R_FAILED(eventWait(event, 0))) return 0;
|
||||||
|
if (R_FAILED(appletHolderPopInteractiveOutData(&s->config->holder, &storage))) return 0;
|
||||||
|
|
||||||
|
rc = appletStorageRead(&storage, 0, &tmphdr, sizeof(tmphdr));
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmphdr.kind == WebSessionReceiveMessageKind_AckBrowserEngine || tmphdr.kind == WebSessionReceiveMessageKind_AckSystemMessage) {
|
||||||
|
u32 msgi = tmphdr.kind != WebSessionReceiveMessageKind_AckBrowserEngine;
|
||||||
|
if (!s->queue[msgi].count) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
s->queue[msgi].count--;
|
||||||
|
rc = appletStorageRead(&storage, 0, data, sizeof(data));
|
||||||
|
}
|
||||||
|
if (R_SUCCEEDED(rc)) s->queue[msgi].cur_size -= *((u32*)(datahdr+1));
|
||||||
|
appletStorageClose(&storage);
|
||||||
|
}
|
||||||
|
else _webSessionStorageEnqueue(&s->storage_queue, &storage);
|
||||||
|
}
|
||||||
|
if (R_FAILED(rc)) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _webSessionSendAck(WebSession *s, u32 size) {
|
||||||
|
Result rc=0;
|
||||||
|
AppletStorage storage;
|
||||||
|
u8 data[0x20]={0};
|
||||||
|
WebSessionMessageHeader *hdr = (WebSessionMessageHeader*)data;
|
||||||
|
|
||||||
|
hdr->kind = WebSessionSendMessageKind_Ack;
|
||||||
|
hdr->size = 0xC;
|
||||||
|
*((u32*)(hdr+1)) = size;
|
||||||
|
|
||||||
|
rc = libappletCreateWriteStorage(&storage, data, sizeof(data));
|
||||||
|
if (R_SUCCEEDED(rc)) rc = appletHolderPushInteractiveInData(&s->config->holder, &storage);
|
||||||
|
if (R_FAILED(rc)) appletStorageClose(&storage);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _webSessionCanSend(WebSession *s, const WebSessionMessageHeader *hdr, u64 storage_size) {
|
||||||
|
u32 msgi = hdr->kind!=WebSessionSendMessageKind_BrowserEngineContent;
|
||||||
|
|
||||||
|
if (s->queue[msgi].count == 0x10) return false;
|
||||||
|
if (s->queue[msgi].cur_size + storage_size > (msgi ? 0x1000 : 0x8000)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _webSessionTrySend(WebSession *s, const WebSessionMessageHeader *hdr, const void* content, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
AppletStorage storage;
|
||||||
|
mutexLock(&s->mutex);
|
||||||
|
if (appletHolderCheckFinished(&s->config->holder)) {
|
||||||
|
*flag = false;
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rc = _webSessionReceiveStorageHandles(s);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
u32 msgi = hdr->kind!=WebSessionSendMessageKind_BrowserEngineContent;
|
||||||
|
|
||||||
|
u64 storage_size = hdr->size+sizeof(*hdr);
|
||||||
|
if (!_webSessionCanSend(s, hdr, storage_size)) {
|
||||||
|
*flag = false;
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = appletCreateStorage(&storage, storage_size);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = appletStorageWrite(&storage, 0, hdr, sizeof(*hdr));
|
||||||
|
if (R_SUCCEEDED(rc) && content && hdr->size) rc = appletStorageWrite(&storage, sizeof(*hdr), content, hdr->size);
|
||||||
|
if (R_FAILED(rc)) appletStorageClose(&storage);
|
||||||
|
if (R_SUCCEEDED(rc)) rc = appletHolderPushInteractiveInData(&s->config->holder, &storage);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
s->queue[msgi].count++;
|
||||||
|
s->queue[msgi].cur_size+= storage_size;
|
||||||
|
*flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result _webSessionTryReceive(WebSession *s, WebSessionMessageHeader *hdr, void* content, u64 size, WebSessionReceiveMessageKind kind, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
s64 tmpsize=0;
|
||||||
|
WebSessionMessageHeader tmphdr={0};
|
||||||
|
AppletStorage *storage = NULL;
|
||||||
|
|
||||||
|
if (hdr==NULL || content==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||||
|
mutexLock(&s->mutex);
|
||||||
|
rc = _webSessionReceiveStorageHandles(s);
|
||||||
|
if (R_FAILED(rc)) {
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if (_webSessionStorageHandleQueueGetCount(&s->storage_queue) < 1) {
|
||||||
|
*flag = false;
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
storage = _webSessionStorageDequeue(&s->storage_queue);
|
||||||
|
rc = appletStorageRead(storage, 0, &tmphdr, sizeof(tmphdr));
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
rc = appletStorageGetSize(storage, &tmpsize);
|
||||||
|
if (R_SUCCEEDED(rc) && tmphdr.size+sizeof(tmphdr) != tmpsize) rc = MAKERESULT(Module_Libnx, LibnxError_ShouldNotHappen);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
if (tmphdr.kind == kind) break;
|
||||||
|
else rc = _webSessionSendAck(s, tmpsize);
|
||||||
|
}
|
||||||
|
if (R_FAILED(rc)) break;
|
||||||
|
appletStorageClose(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) {
|
||||||
|
*hdr = tmphdr;
|
||||||
|
if (tmphdr.size) rc = appletStorageRead(storage, sizeof(tmphdr), content, tmphdr.size < size ? tmphdr.size : size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc)) rc = _webSessionSendAck(s, tmpsize);
|
||||||
|
appletStorageClose(storage);
|
||||||
|
if (R_SUCCEEDED(rc)) *flag = true;
|
||||||
|
mutexUnlock(&s->mutex);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionAppear(WebSession *s, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
bool tmpflag=0;
|
||||||
|
WebSessionMessageHeader hdr = {.kind = WebSessionSendMessageKind_SystemMessageAppear, .size = 0};
|
||||||
|
do {
|
||||||
|
rc = _webSessionTrySend(s, &hdr, NULL, &tmpflag);
|
||||||
|
if (R_SUCCEEDED(rc) && tmpflag) {
|
||||||
|
*flag = true;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if (R_FAILED(rc)) return rc;
|
||||||
|
} while (appletHolderWaitInteractiveOut(&s->config->holder));
|
||||||
|
*flag = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionTrySendContentMessage(WebSession *s, const char *content, u32 size, bool *flag) {
|
||||||
|
WebSessionMessageHeader hdr = {.kind = WebSessionSendMessageKind_BrowserEngineContent, .size = size};
|
||||||
|
return _webSessionTrySend(s, &hdr, content, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result webSessionTryReceiveContentMessage(WebSession *s, char *content, u64 size, u64 *out_size, bool *flag) {
|
||||||
|
Result rc=0;
|
||||||
|
bool tmpflag=0;
|
||||||
|
WebSessionMessageHeader hdr={0};
|
||||||
|
if (content==NULL || out_size==NULL) return MAKERESULT(Module_Libnx, LibnxError_BadInput);
|
||||||
|
|
||||||
|
do {
|
||||||
|
rc = _webSessionTryReceive(s, &hdr, content, size, WebSessionReceiveMessageKind_BrowserEngineContent, &tmpflag);
|
||||||
|
if (R_FAILED(rc) || !tmpflag) {
|
||||||
|
*flag = false;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
} while(hdr.kind!=WebSessionReceiveMessageKind_BrowserEngineContent);
|
||||||
|
|
||||||
|
u64 tmp_size = hdr.size;
|
||||||
|
*out_size = tmp_size;
|
||||||
|
if (tmp_size > size) tmp_size = size;
|
||||||
|
if (tmp_size) content[tmp_size-1] = 0; // sdknso doesn't check tmp_size here.
|
||||||
|
|
||||||
|
*flag = true;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user