Skip to content

Commit

Permalink
Add Switch.Service class
Browse files Browse the repository at this point in the history
  • Loading branch information
TooTallNate committed Dec 5, 2024
1 parent 2daafbd commit 600ac89
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-rice-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nx.js/runtime": patch
---

Add `Switch.Service` class
5 changes: 5 additions & 0 deletions .changeset/proud-dogs-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@nx.js/constants": minor
---

Add `SfBufferAttr` and `SfOutHandleAttr` enums
1 change: 1 addition & 0 deletions packages/constants/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export * from './errno';
export * from './fs';
export * from './gamepad';
export * from './hid';
export * from './service';
export * from './swkbd';
16 changes: 16 additions & 0 deletions packages/constants/src/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export enum SfBufferAttr {
In = 1 << 0,
Out = 1 << 1,
HipcMapAlias = 1 << 2,
HipcPointer = 1 << 3,
FixedSize = 1 << 4,
HipcAutoSelect = 1 << 5,
HipcMapTransferAllowsNonSecure = 1 << 6,
HipcMapTransferAllowsNonDevice = 1 << 7,
}

export enum SfOutHandleAttr {
None = 0,
HipcCopy = 1,
HipcMove = 2,
}
5 changes: 5 additions & 0 deletions packages/runtime/src/$.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
ProfileUid,
SaveData,
SaveDataCreationInfo,
Service,
Stats,
Versions,
} from './switch';
Expand Down Expand Up @@ -223,6 +224,10 @@ export interface Init {
nsAppNew(id: string | bigint | ArrayBuffer | null): Application;
nsAppNext(index: number): bigint | null;

// service.c
serviceInit(c: ClassOf<Service>): () => void;
serviceNew(name: string): Service;

// software-keyboard.c
swkbdCreate(fns: {
onCancel: (this: VirtualKeyboard) => void;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/src/switch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './irsensor';
export * from './profile';
export * from './album';
export * from './file-system';
export * from './service';
export { Socket, Server };

export type PathLike = string | URL;
Expand Down
70 changes: 70 additions & 0 deletions packages/runtime/src/switch/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { $ } from '../$';
import { proto, stub } from '../utils';

export interface ServiceDispatchParams {
//Handle target_session;
//u32 context;

//SfBufferAttrs buffer_attrs;
//SfBuffer buffers[8];
bufferAttrs: number[];
buffers: ArrayBuffer[];

//bool in_send_pid;

//u32 in_num_objects;
//const Service* in_objects[8];

//u32 in_num_handles;
//Handle in_handles[8];

//u32 out_num_objects;
//Service* out_objects;

//SfOutHandleAttrs out_handle_attrs;
//Handle* out_handles;
}

export class Service {
constructor(name: string) {
return proto($.serviceNew(name), Service);
}

isActive() {
stub();
}

isOverride() {
stub();
}

dispatch(rid: number, dispatchParams?: ServiceDispatchParams) {
return this.dispatchInOut(rid, undefined, undefined, dispatchParams);
}

dispatchIn(
rid: number,
inData: ArrayBuffer,
dispatchParams?: ServiceDispatchParams,
) {
return this.dispatchInOut(rid, inData, undefined, dispatchParams);
}

dispatchOut(
rid: number,
outData: ArrayBuffer,
dispatchParams?: ServiceDispatchParams,
) {
return this.dispatchInOut(rid, undefined, outData, dispatchParams);
}

dispatchInOut(
rid: number,
inData?: ArrayBuffer,
outData?: ArrayBuffer,
dispatchParams?: ServiceDispatchParams,
) {
stub();
}
}
$.serviceInit(Service);
2 changes: 2 additions & 0 deletions source/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "nifm.h"
#include "ns.h"
#include "poll.h"
#include "service.h"
#include "software-keyboard.h"
#include "tcp.h"
#include "tls.h"
Expand Down Expand Up @@ -629,6 +630,7 @@ int main(int argc, char *argv[]) {
nx_init_irs(ctx, nx_ctx->init_obj);
nx_init_nifm(ctx, nx_ctx->init_obj);
nx_init_ns(ctx, nx_ctx->init_obj);
nx_init_service(ctx, nx_ctx->init_obj);
nx_init_tcp(ctx, nx_ctx->init_obj);
nx_init_tls(ctx, nx_ctx->init_obj);
nx_init_url(ctx, nx_ctx->init_obj);
Expand Down
173 changes: 173 additions & 0 deletions source/service.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#include "service.h"
#include "error.h"

static JSClassID nx_service_class_id;

typedef struct {
Service service;
} nx_service_t;

static void finalizer_service(JSRuntime *rt, JSValue val) {
nx_service_t *data = JS_GetOpaque(val, nx_service_class_id);
if (data) {
serviceClose(&data->service);
js_free_rt(rt, data);
}
}

static JSValue nx_service_new(JSContext *ctx, JSValueConst this_val, int argc,
JSValueConst *argv) {
nx_service_t *data = js_mallocz(ctx, sizeof(nx_service_t));
if (!data) {
return JS_EXCEPTION;
}

const char *name = JS_ToCString(ctx, argv[0]);
if (!name) {
return JS_EXCEPTION;
}

Result rc = smGetService(&data->service, name);
JS_FreeCString(ctx, name);

if (R_FAILED(rc)) {
return nx_throw_libnx_error(ctx, rc, "smGetService()");
}

JSValue obj = JS_NewObjectClass(ctx, nx_service_class_id);
JS_SetOpaque(obj, data);

return obj;
}

static JSValue nx_service_is_active(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
nx_service_t *data = JS_GetOpaque2(ctx, this_val, nx_service_class_id);
if (!data)
return JS_EXCEPTION;

return JS_NewBool(ctx, serviceIsActive(&data->service));
}

static JSValue nx_service_is_override(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
nx_service_t *data = JS_GetOpaque2(ctx, this_val, nx_service_class_id);
if (!data)
return JS_EXCEPTION;

return JS_NewBool(ctx, serviceIsOverride(&data->service));
}

static JSValue nx_service_dispatch_in_out(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
nx_service_t *data = JS_GetOpaque2(ctx, this_val, nx_service_class_id);
if (!data)
return JS_EXCEPTION;

u32 rid;
if (JS_ToUint32(ctx, &rid, argv[0])) {
return JS_EXCEPTION;
}

size_t in_data_size = 0;
void *in_data = NULL;
if (JS_IsArrayBuffer(argv[1])) {
in_data = JS_GetArrayBuffer(ctx, &in_data_size, argv[1]);
}

size_t out_data_size = 0;
void *out_data = NULL;
if (JS_IsArrayBuffer(argv[2])) {
out_data = JS_GetArrayBuffer(ctx, &out_data_size, argv[2]);
}

SfDispatchParams disp = {0};
if (JS_IsObject(argv[3])) {
JSValue buffer_attrs_val =
JS_GetPropertyStr(ctx, argv[3], "bufferAttrs");
if (JS_IsArray(ctx, buffer_attrs_val)) {
JSValue length_val =
JS_GetPropertyStr(ctx, buffer_attrs_val, "length");
u32 length;
if (JS_ToUint32(ctx, &length, length_val)) {
JS_FreeValue(ctx, buffer_attrs_val);
JS_FreeValue(ctx, length_val);
return JS_EXCEPTION;
}
for (u32 i = 0; i < length; i++) {
JSValue v = JS_GetPropertyUint32(ctx, buffer_attrs_val, i);
if (JS_IsNumber(v)) {
u32 attr;
if (JS_ToUint32(ctx, &attr, v)) {
JS_FreeValue(ctx, buffer_attrs_val);
JS_FreeValue(ctx, length_val);
return JS_EXCEPTION;
}
// TODO: all `attr` props
disp.buffer_attrs.attr0 = attr;
}
JS_FreeValue(ctx, v);
}
JS_FreeValue(ctx, length_val);
}
JS_FreeValue(ctx, buffer_attrs_val);

JSValue buffers_val = JS_GetPropertyStr(ctx, argv[3], "buffers");
if (JS_IsArray(ctx, buffers_val)) {
JSValue length_val = JS_GetPropertyStr(ctx, buffers_val, "length");
u32 length;
if (JS_ToUint32(ctx, &length, length_val)) {
JS_FreeValue(ctx, buffers_val);
JS_FreeValue(ctx, length_val);
return JS_EXCEPTION;
}
for (u32 i = 0; i < length; i++) {
JSValue v = JS_GetPropertyUint32(ctx, buffers_val, i);
if (JS_IsArrayBuffer(v)) {
disp.buffers[i].ptr =
JS_GetArrayBuffer(ctx, &disp.buffers[i].size, v);
}
JS_FreeValue(ctx, v);
}
}
JS_FreeValue(ctx, buffers_val);
}

Result rc = serviceDispatchImpl(&data->service, rid, in_data, in_data_size,
out_data, out_data_size, disp);

if (R_FAILED(rc)) {
return nx_throw_libnx_error(ctx, rc, "serviceDispatchOut()");
}

return JS_UNDEFINED;
}

static JSValue nx_service_init(JSContext *ctx, JSValueConst this_val, int argc,
JSValueConst *argv) {
JSValue proto = JS_GetPropertyStr(ctx, argv[0], "prototype");
NX_DEF_FUNC(proto, "isActive", nx_service_is_active, 0);
NX_DEF_FUNC(proto, "isOverride", nx_service_is_override, 0);
NX_DEF_FUNC(proto, "dispatchInOut", nx_service_dispatch_in_out, 3);
JS_FreeValue(ctx, proto);
return JS_UNDEFINED;
}

static const JSCFunctionListEntry function_list[] = {
JS_CFUNC_DEF("serviceInit", 3, nx_service_init),
JS_CFUNC_DEF("serviceNew", 3, nx_service_new),
};

void nx_init_service(JSContext *ctx, JSValueConst init_obj) {
JSRuntime *rt = JS_GetRuntime(ctx);

JS_NewClassID(rt, &nx_service_class_id);
JSClassDef nx_service_class = {
"Service",
.finalizer = finalizer_service,
};
JS_NewClass(rt, nx_service_class_id, &nx_service_class);

JS_SetPropertyFunctionList(ctx, init_obj, function_list,
countof(function_list));
}
4 changes: 4 additions & 0 deletions source/service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once
#include "types.h"

void nx_init_service(JSContext *ctx, JSValueConst init_obj);

0 comments on commit 600ac89

Please sign in to comment.