Use js to communicate with ukagaka in environments such as web pages or node.js in order to exchange information. See ukagaka & SSTP for details.
If you use npm, you can use npm to install jsstp.
npm i jsstp
After that, use import
to bring in jsstp in js.
import jsstp from "jsstp";
//or
var {jsstp}=await import("jsstp");
In CommonJS, you can also use require
to introduce jsstp.
var jsstp=require('jsstp');
If you're a nostalgist, you can access jsstp's source code via CDN.
<script src="https://cdn.jsdelivr.net/gh/ukatech/jsstp-lib@v3.2.0.0/dist/jsstp.min.js"></script>
Or load jsstp dynamically in js.
var {jsstp}=await import("https://cdn.jsdelivr.net/gh/ukatech/jsstp-lib@v3.2.0.0/dist/jsstp.mjs");
Even if you use CDN and write js code by hand, you can use jsstp's type definition file in your IDE to get code hints.
First make sure your IDE has access to jsstp. You can probably install it globally to use it without disturbing the workspace file.
npm i -g jsstp
Afterwards, add a type import to the head of the file using jsstp. According to the types convention, this declaration must precede any formal code.
/// <reference types="jsstp" />
Finally, declare the type of jsstp before its declaration with a JSDoc comment.
/** @type {typeof import("jsstp").jsstp} */
var jsstp;
The type definition of jsstp provides support for Chinese, Japanese and English. Normally you can specify the loaded language like this
/// <reference types="jsstp/cn" />
// or
/// <reference types="jsstp/jp" />
// or
/// <reference types="jsstp/en" />
However, if your IDE bugs when used this way (or you don't want to specify the language every time), you might consider manually modifying the types
field in package.json
to specify the default language
{
"types": "dist/en/jsstp.d.ts"
}
jsstp now has a dedicated documentation page!
You can visit https://ukatech.github.io/jsstp-lib/doc for more specialized information.
While looking the documentation, you can try out the various features of jsstp in the jsstp playground
You may need to check if the ghost is available before jsstp related operations.
if (!await jsstp.available())
console.log("Ghost is not available, please check if ghost is running");
jsstp used to support passing callback functions as arguments before 2.0, but this is no longer supported.
You can use Promise
or async
/await
to get the return value if you need to.
You can use jsstp.SEND
to send a message.
jsstp.SEND(
{//event message
"Event": "OnTest",
"Script": "\\0Hello, World!\\e"
}
).then((data) => {
console.log("head: " + data.head);
console.log(JSON.stringify(data));
console.log(data["Script"]);
});
jsstp supports all the sstp base operations: jsstp.[SEND|NOTIFY|COMMUNICATE|EXECUTE|GIVE]
can be called.
If you like nostalgia and just want to get the message itself, you can use jsstp.[SEND|NOTIFY|COMMUNICATE|EXECUTE|GIVE].get_raw
If you just want to trigger the event and don't need to customize it to send more complex messages, you can write it like this:
let data = await jsstp.OnTest("from jsstp.js!", 123123);
This is equivalent to:
let data = await jsstp.SEND({
"Event": "OnTest",
"Reference0": "from jsstp.js!",
"Reference1": 123123
});
You can write this for all events, but if the event doesn't start with On
, you need to prefix the event name with On_
when accessing jsstp so that it recognizes that you want to trigger the event.
You can also use jsstp.event.eventName(parameter)
to trigger the event, so you don't need to prefix the event name with On_
After getting the return content, which is of type jsstp.sstp_info_t
, there are various ways to use it.
info_object
:data.keys; //Get all keys
data.values; //Get all values
data.entries; //Get all key-value pairs
data.length; //Get the number of key-value pairs
data.forEach((value, key) => console.log(key + "=" + value)); //Iterate through all key-value pairs: if the iteration function returns a value, that value will be updated to this key-value pair
//Omit the key argument to iterate over just the values
data.map((value, key) => value + "1"); //Iterate over all key-value pairs and return an array of the values returned by the iterator function
//Omitting the key argument allows you to iterate over just the values
jsstp.base_sstp_info_t
:data.status_code; //Get the status code
data.head; //Get the message header
data.Script; //Get the value of the Script key in the message (other keys can also be obtained this way)
data.status_code_text; //Get the text of the status code in the message header
jsstp.sstp_info_t
:data.get_passthrough("Result");
//Get the value of a key of `X-SSTP-PassThru` in the message, equivalent to `data["X-SSTP-PassThru-Result"]`
//You can also just use `data.Result` or `data["Result"]` to get the value of `X-SSTP-PassThru-Result`: this might be cleaner
data.passthroughs; //Get all `X-SSTP-PassThru` key-value pairs
data.raw; //Remove the proxy and access the original object
sstp_info_t
is wrapped in a proxy since its construction, and given that in most cases developers don't need to access non-X-SSTP-PassThru
key-value pairs, this proxy will preferentially return the X-SSTP-PassThru-{key}
value when you access a key for which an X-SSTP-PassThru
version exists.
In other words, if the returned message has a Script
key and an X-SSTP-PassThru-Script
key, then data.Script
or data["Script"]
will return the value of X-SSTP-PassThru-Script
, while data.raw.Script
and data.raw["Script"]
will return the value of Script
.
In most cases, this proxy will reduce the amount of code you have to work with, but always remember to use data.raw
to access the original object when you need to access non-X-SSTP-PassThru
key-value pairs.
If you want to get whether ghost supports a certain event or not, you can write it like this:
let result = await jsstp.has_event("OnTest"); //This is almost the same as jsstp.event.Has_Event(event_name, security_level).then(({ Result }) => Result == "1")!
console.log(result);
If you want to query events in bulk (like Ukadoc does!) , you can use jsstp.new_event_queryer()
to get a queryer.
let queryer = await jsstp.new_event_queryer();
queryer is of type jsstp.ghost_events_queryer_t
and is used in various ways.
queryer.check_event("OnTest").then(result => console.log(result));
The queryer, like jsstp
, checks the event with an optional argument that specifies the event's security level. The default security level varies with the environment in which jsstp
is running:
If jsstp is running in node.js, the security level is local
. If jsstp is running in a browser, the security level is external
(because jsstp in a browser can only trigger external events!)
If you want to modify the query local event, you need to specify the security level as local
, like this:
queryer.check_event("OnBoot", "local");
jsstp.has_event("OnBoot", "local"); //Use jsstp like this
The queryer also supports some quick detection.
The queryer is bound to the jsstp instance that constructed it; if you want the queryer to point to a specific ghost, modify the default additional messages by setting jsstp.default_info
and use reset
to clear the cache.
//Use the hwnd obtained in fmo; this avoids awkward situations caused by renaming
jsstp.default_info.ReceiverGhostHWnd = fmo[uuid].hwnd; //See below for how to get fmo, this is just an example
await queryer.reset();
If you're sure your ghost name is unique enough, you can also just use the ghost name. Only one of these two methods will work.
jsstp.default_info.ReceiverGhostName = "橘花";
await queryer.reset();
The queryer also supports some quick tests to check the availability of the queryer.
if (!queryer.available)
console.info("Could not get a list of supported events"); //queryer is not available, you need to alert the user to update the ghost or give feedback to its author: jsstp uses the `Has_Event` event to check the availability of events, as does the ghost terminal.
if (!queryer.fast_query_available)
console.info("Can't get a list of supported events quickly"); //This won't affect usage, it will just cause a query request to be made for uncached events: if ghost supports `Get_Supported_Events` events the queryer will use it to get a list of events (which will be much faster!)
else
console.info("Hell yeah!");
If you want to get fmo information, you can write it like this:
let fmo = await jsstp.get_fmo_infos();
if (fmo.available)
console.log(fmo);
The type of fmo is jsstp.fmo_info_t
and is used in various ways.
fmo_info_t
is a specialised base_sstp_info_t
, so you can use all the methods of base_sstp_info_t
on it (that is, all the methods of sstp_info_t
except get_passthrough
).
It also has some special methods:
fmo.uuids; //Get all uuids, equivalent to `fmo.keys`
fmo.get_uuid_by("fullname", "Taromati2"); //Get the uuid of the specified attribute value equal to the specified value
fmo.get_list_of("fullname"); //Get all values of the specified attribute
fmo.available; //Get whether fmo has content
Each key-value pair of fmo is String:info_object
, the key is the uuid and the value is the fmo information corresponding to that uuid.
You can still use the member methods of info_object
to manipulate the fmo information in fmo (see the introduction to sstp_info_t
above).
If you still don't understand it, you can check the structure of fmo in the console or look at the source code of jsstp.