updated codestyle
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Make-Without-sqlite3 (push) Successful in 6s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-CMake-Without-sqlite3 (push) Successful in 9s
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Meson-Without-sqlite3 (push) Successful in 7s

This commit is contained in:
wt
2025-11-18 11:48:46 +07:00
parent 193779bd13
commit 36aa1bea2a
12 changed files with 18657 additions and 4237 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ OBJS = $(SRCS:.c=.o)
TARGET = wterm
BUILD_DIR=./build
CROSS_COMPILE =
LIBS = -lpthread
LIBS = -lpthread
# -lcrypto -lssl
USE_SQLITE3 ?= 0
WERROR ?= 0
+2244 -2570
View File
File diff suppressed because it is too large Load Diff
+218 -129
View File
@@ -24,23 +24,27 @@
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#if !defined(__WINDOWS__) && \
(defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
/* When compiling for windows, we specify a specific calling convention to avoid
issues where we are being called from a project with a different default calling
convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever
dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you
want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you
want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
For *nix builds that support visibility attribute, you can define similar
behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
@@ -48,31 +52,35 @@ or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way
CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
/* export symbols by default, this is necessary for copy pasting the C and
* header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && \
!defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && \
defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
@@ -87,115 +95,146 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
typedef struct cJSON {
/* next/prev allow you to walk array/object chains. Alternatively, use
* GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of
* the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
/* The item's name string, if this item is the child of, or is in the list of
* subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
typedef struct cJSON_Hooks {
/* malloc/free are CDECL on Windows regardless of the default calling
* convention of the compiler, so ensure the hooks allow passing those
* functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void(CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse
* them. This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* Limits the length of circular references can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
/* Limits the length of circular references can be before cJSON rejects to parse
* them. This is to prevent stack overflows. */
#ifndef CJSON_CIRCULAR_LIMIT
#define CJSON_CIRCULAR_LIMIT 10000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
CJSON_PUBLIC(const char *) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
/* Memory Management: the caller is always responsible to free the results from
* all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib
* free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is
* cJSON_PrintPreallocated, where the caller has full responsibility of the
* buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate.
*/
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *)
cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null
* terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then
* return_parse_end will contain a pointer to the error so will match
* cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *)
cJSON_ParseWithOpts(const char *value, const char **return_parse_end,
cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *)
cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length,
const char **return_parse_end,
cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess
* at the final size. guessing well reduces reallocation. fmt=0 gives
* unformatted, =1 gives formatted */
CJSON_PUBLIC(char *)
cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with
* given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will
* use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool)
cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length,
const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
/* Retrieve item number "index" from array "array". Returns NULL if
* unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(cJSON *)
cJSON_GetObjectItem(const cJSON *const object, const char *const string);
CJSON_PUBLIC(cJSON *)
cJSON_GetObjectItemCaseSensitive(const cJSON *const object,
const char *const string);
CJSON_PUBLIC(cJSON_bool)
cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error.
* You'll probably need to look a few chars back to make sense of it. Defined
* when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON *const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
@@ -218,84 +257,134 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
* The parameter count cannot be greater than the number of elements in the
* number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
CJSON_PUBLIC(cJSON *)
cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
CJSON_PUBLIC(cJSON_bool)
cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and
* will definitely survive the cJSON object. WARNING: When this function was
* used, make sure to always check that (item->type & cJSON_StringIsConst) is
* zero before writing to `item->string` */
CJSON_PUBLIC(cJSON_bool)
cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you
* want to add an existing cJSON to a new cJSON, but don't want to corrupt your
* existing cJSON. */
CJSON_PUBLIC(cJSON_bool)
cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool)
cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *)
cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *)
cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *)
cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void)
cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void)
cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool)
cJSON_InsertItemInArray(
cJSON *array, int which,
cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool)
cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item,
cJSON *replacement);
CJSON_PUBLIC(cJSON_bool)
cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool)
cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool)
cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string,
cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new
* memory that will need to be released. With recurse!=0, it will duplicate any
* children connected to the item. The item->next and ->prev pointers are always
* zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or
* invalid, they will be considered unequal. case_sensitive determines if object
* keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool)
cJSON_Compare(const cJSON *const a, const cJSON *const b,
const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable address area. */
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from
* strings. The input pointer json cannot point to a read-only address area,
* such as a string constant, but should point to a readable and writable
* address area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON *)
cJSON_AddNullToObject(cJSON *const object, const char *const name);
CJSON_PUBLIC(cJSON *)
cJSON_AddTrueToObject(cJSON *const object, const char *const name);
CJSON_PUBLIC(cJSON *)
cJSON_AddFalseToObject(cJSON *const object, const char *const name);
CJSON_PUBLIC(cJSON *)
cJSON_AddBoolToObject(cJSON *const object, const char *const name,
const cJSON_bool boolean);
CJSON_PUBLIC(cJSON *)
cJSON_AddNumberToObject(cJSON *const object, const char *const name,
const double number);
CJSON_PUBLIC(cJSON *)
cJSON_AddStringToObject(cJSON *const object, const char *const name,
const char *const string);
CJSON_PUBLIC(cJSON *)
cJSON_AddRawToObject(cJSON *const object, const char *const name,
const char *const raw);
CJSON_PUBLIC(cJSON *)
cJSON_AddObjectToObject(cJSON *const object, const char *const name);
CJSON_PUBLIC(cJSON *)
cJSON_AddArrayToObject(cJSON *const object, const char *const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* When assigning an integer value, it needs to be propagated to valuedouble
* too. */
#define cJSON_SetIntValue(object, number) \
((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
#define cJSON_SetNumberValue(object, number) \
((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type
* of object is cJSON_String */
CJSON_PUBLIC(char *)
cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* If the object is not a boolean type this does nothing and returns
* cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) \
((object != NULL && ((object)->type & (cJSON_False | cJSON_True))) \
? (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) | \
((boolValue) ? cJSON_True : cJSON_False) \
: cJSON_Invalid)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
#define cJSON_ArrayForEach(element, array) \
for (element = (array != NULL) ? (array)->child : NULL; element != NULL; \
element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
/* malloc/free objects using the malloc/free functions that have been set with
* cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
+268 -251
View File
@@ -1,13 +1,13 @@
#include "terminal.h"
#include <cJSON.h>
#include <errno.h>
#include <mongoose.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <mongoose.h>
#include <cJSON.h>
#include "terminal.h"
#include <sys/wait.h>
#define HTTP_PORT "8888"
#define STATIC_DIR "./static/"
@@ -16,284 +16,301 @@ static const char *s_http_addr = "http://0.0.0.0:8888";
static struct mg_mgr mgr;
struct client_data {
struct terminal_session term;
bool terminal_ready;
struct terminal_session term;
bool terminal_ready;
};
// Функция для логирования запросов
static void log_request(struct mg_connection *c, struct mg_http_message *hm) {
printf("HTTP Request: %.*s %.*s\n", (int)hm->method.len, hm->method.buf,
(int)hm->uri.len, hm->uri.buf);
printf("HTTP Request: %.*s %.*s\n", (int)hm->method.len, hm->method.buf,
(int)hm->uri.len, hm->uri.buf);
}
// Проверяем, жив ли дочерний процесс
static bool is_process_alive(pid_t pid) {
if (pid <= 0) return false;
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
if (result == 0) {
// Процесс все еще работает
return true;
} else if (result == -1) {
// Ошибка
if (errno == ECHILD) {
// Процесс не существует
return false;
}
perror("waitpid");
return false;
} else {
// Процесс завершился
return false;
if (pid <= 0)
return false;
int status;
pid_t result = waitpid(pid, &status, WNOHANG);
if (result == 0) {
// Процесс все еще работает
return true;
} else if (result == -1) {
// Ошибка
if (errno == ECHILD) {
// Процесс не существует
return false;
}
perror("waitpid");
return false;
} else {
// Процесс завершился
return false;
}
}
// Перезапускаем терминальную сессию
static void restart_terminal_session(struct mg_connection *c, struct client_data *cd) {
if (!cd) return;
printf("Restarting terminal session...\n");
// Уничтожаем старую сессию
if (cd->terminal_ready) {
destroy_terminal_session(&cd->term);
}
// Создаем новую сессию
const char *shell = getenv("SHELL");
if (!shell) shell = "/bin/bash";
if (create_terminal_session(&cd->term, shell) == 0) {
cd->terminal_ready = true;
mg_ws_send(c, "\r\n*** Terminal restarted ***\r\n", 29, WEBSOCKET_OP_TEXT);
} else {
mg_ws_send(c, "\r\n*** Failed to restart terminal ***\r\n", 37, WEBSOCKET_OP_TEXT);
cd->terminal_ready = false;
}
static void restart_terminal_session(struct mg_connection *c,
struct client_data *cd) {
if (!cd)
return;
printf("Restarting terminal session...\n");
// Уничтожаем старую сессию
if (cd->terminal_ready) {
destroy_terminal_session(&cd->term);
}
// Создаем новую сессию
const char *shell = getenv("SHELL");
if (!shell)
shell = "/bin/bash";
if (create_terminal_session(&cd->term, shell) == 0) {
cd->terminal_ready = true;
mg_ws_send(c, "\r\n*** Terminal restarted ***\r\n", 29, WEBSOCKET_OP_TEXT);
} else {
mg_ws_send(c, "\r\n*** Failed to restart terminal ***\r\n", 37,
WEBSOCKET_OP_TEXT);
cd->terminal_ready = false;
}
}
// Обработчик WebSocket сообщений
static void handle_websocket_message(struct mg_connection *c, struct mg_ws_message *wm, struct client_data *cd) {
if (!cd) return;
if (wm->data.len == 0) {
return;
static void handle_websocket_message(struct mg_connection *c,
struct mg_ws_message *wm,
struct client_data *cd) {
if (!cd)
return;
if (wm->data.len == 0) {
return;
}
// Парсим JSON для проверки resize сообщения
cJSON *json = cJSON_ParseWithLength(wm->data.buf, wm->data.len);
if (json != NULL) {
cJSON *cols = cJSON_GetObjectItemCaseSensitive(json, "cols");
cJSON *rows = cJSON_GetObjectItemCaseSensitive(json, "rows");
if (cJSON_IsNumber(cols) && cJSON_IsNumber(rows)) {
printf("Resizing terminal to %dx%d\n", rows->valueint, cols->valueint);
resize_terminal(&cd->term, rows->valueint, cols->valueint);
cJSON_Delete(json);
return;
}
// Парсим JSON для проверки resize сообщения
cJSON *json = cJSON_ParseWithLength(wm->data.buf, wm->data.len);
if (json != NULL) {
cJSON *cols = cJSON_GetObjectItemCaseSensitive(json, "cols");
cJSON *rows = cJSON_GetObjectItemCaseSensitive(json, "rows");
if (cJSON_IsNumber(cols) && cJSON_IsNumber(rows)) {
printf("Resizing terminal to %dx%d\n", rows->valueint, cols->valueint);
resize_terminal(&cd->term, rows->valueint, cols->valueint);
cJSON_Delete(json);
return;
}
cJSON_Delete(json);
}
// Проверяем, не команда ли это exit
if (wm->data.len >= 4 && strncmp(wm->data.buf, "exit", 4) == 0) {
printf("Exit command detected, restarting terminal session\n");
write_to_terminal(&cd->term, wm->data.buf, wm->data.len);
// Даем команде выполниться, затем перезапускаем
usleep(100);
restart_terminal_session(c, cd);
return;
}
// Обычный ввод от пользователя
cJSON_Delete(json);
}
// Проверяем, не команда ли это exit
if (wm->data.len >= 4 && strncmp(wm->data.buf, "exit", 4) == 0) {
printf("Exit command detected, restarting terminal session\n");
write_to_terminal(&cd->term, wm->data.buf, wm->data.len);
// Даем команде выполниться, затем перезапускаем
usleep(100);
restart_terminal_session(c, cd);
return;
}
// Обычный ввод от пользователя
write_to_terminal(&cd->term, wm->data.buf, wm->data.len);
}
// Обработчик HTTP запросов
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
log_request(c, hm);
if (mg_match(hm->uri, mg_str("/ws"), nullptr)) {
// Проверяем, нет ли уже активного соединения
if (c->fn_data != NULL) {
printf("WebSocket connection already exists for this connection, cleaning up...\n");
struct client_data *old_cd = (struct client_data *)c->fn_data;
destroy_terminal_session(&old_cd->term);
free(old_cd);
c->fn_data = NULL;
}
// Upgrade до WebSocket
struct client_data *cd = calloc(1, sizeof(struct client_data));
if (!cd) {
mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Memory allocation failed");
return;
}
// Создаем терминальную сессию
const char *shell = getenv("SHELL");
if (!shell) shell = "/bin/bash";
printf("Creating new terminal session with shell: %s\n", shell);
if (create_terminal_session(&cd->term, shell) != 0) {
mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Failed to create terminal session");
free(cd);
return;
}
cd->terminal_ready = true;
c->fn_data = cd;
// Upgrade to WebSocket
struct mg_str *ws_proto = mg_http_get_header(hm, "Sec-WebSocket-Protocol");
if (ws_proto != NULL) {
mg_ws_upgrade(c, hm, ws_proto->buf);
} else {
mg_ws_upgrade(c, hm, NULL);
}
printf("WebSocket upgrade completed\n");
} else if (mg_match(hm->uri, mg_str("/"), nullptr)) {
// Главная страница
struct mg_http_serve_opts opts = { .root_dir = STATIC_DIR };
mg_http_serve_file(c, hm, "./static/index.html", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm.js"), nullptr)) {
// xterm.js
struct mg_http_serve_opts opts = { .root_dir = STATIC_DIR };
mg_http_serve_file(c, hm, "./static/xterm.js", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm.css"), nullptr)) {
// xterm.css
struct mg_http_serve_opts opts = { .root_dir = STATIC_DIR };
mg_http_serve_file(c, hm, "./static/xterm.css", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm-addon-fit.js"), nullptr)) {
// xterm-addon-fit.js
struct mg_http_serve_opts opts = { .root_dir = STATIC_DIR };
mg_http_serve_file(c, hm, "./static/xterm-addon-fit.js", &opts);
} else {
mg_http_reply(c, 404, "Content-Type: text/plain\r\n", "Not Found");
}
} else if (ev == MG_EV_WS_OPEN) {
// WebSocket соединение установлено
printf("WebSocket connection opened\n");
struct client_data *cd = (struct client_data *)c->fn_data;
if (cd) {
mg_ws_send(c, "Terminal ready - type 'exit' to restart session\r\n", 49, WEBSOCKET_OP_TEXT);
}
} else if (ev == MG_EV_WS_MSG) {
// Сообщение от WebSocket клиента
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
struct client_data *cd = (struct client_data *)c->fn_data;
handle_websocket_message(c, wm, cd);
} else if (ev == MG_EV_CLOSE) {
// Закрытие соединения
struct client_data *cd = (struct client_data *)c->fn_data;
if (cd) {
printf("WebSocket connection closed, cleaning up...\n");
destroy_terminal_session(&cd->term);
free(cd);
c->fn_data = NULL;
}
} else if (ev == MG_EV_POLL) {
// Проверяем данные от терминала и отправляем через WebSocket
struct mg_connection *conn;
for (conn = mgr.conns; conn != NULL; conn = conn->next) {
if (!conn->is_websocket) continue;
struct client_data *cd = (struct client_data *)conn->fn_data;
if (cd && cd->terminal_ready) {
// Проверяем, не завершился ли процесс
if (!is_process_alive(cd->term.child_pid)) {
printf("Terminal process died, restarting...\n");
restart_terminal_session(conn, cd);
continue;
}
// Читаем данные из терминала
char buffer[1024];
ssize_t bytes_read = read_from_terminal(&cd->term, buffer, sizeof(buffer));
if (bytes_read > 0) {
mg_ws_send(conn, buffer, bytes_read, WEBSOCKET_OP_BINARY);
} else if (bytes_read == 0) {
// EOF - процесс завершился
printf("EOF from terminal, restarting...\n");
restart_terminal_session(conn, cd);
} else if (bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
// Ошибка чтения
printf("Error reading from terminal: %s\n", strerror(errno));
restart_terminal_session(conn, cd);
}
}
}
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
log_request(c, hm);
if (mg_match(hm->uri, mg_str("/ws"), nullptr)) {
// Проверяем, нет ли уже активного соединения
if (c->fn_data != NULL) {
printf("WebSocket connection already exists for this connection, "
"cleaning up...\n");
struct client_data *old_cd = (struct client_data *)c->fn_data;
destroy_terminal_session(&old_cd->term);
free(old_cd);
c->fn_data = NULL;
}
// Upgrade до WebSocket
struct client_data *cd = calloc(1, sizeof(struct client_data));
if (!cd) {
mg_http_reply(c, 500, "Content-Type: text/plain\r\n",
"Memory allocation failed");
return;
}
// Создаем терминальную сессию
const char *shell = getenv("SHELL");
if (!shell)
shell = "/bin/bash";
printf("Creating new terminal session with shell: %s\n", shell);
if (create_terminal_session(&cd->term, shell) != 0) {
mg_http_reply(c, 500, "Content-Type: text/plain\r\n",
"Failed to create terminal session");
free(cd);
return;
}
cd->terminal_ready = true;
c->fn_data = cd;
// Upgrade to WebSocket
struct mg_str *ws_proto =
mg_http_get_header(hm, "Sec-WebSocket-Protocol");
if (ws_proto != NULL) {
mg_ws_upgrade(c, hm, ws_proto->buf);
} else {
mg_ws_upgrade(c, hm, NULL);
}
printf("WebSocket upgrade completed\n");
} else if (mg_match(hm->uri, mg_str("/"), nullptr)) {
// Главная страница
struct mg_http_serve_opts opts = {.root_dir = STATIC_DIR};
mg_http_serve_file(c, hm, "./static/index.html", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm.js"), nullptr)) {
// xterm.js
struct mg_http_serve_opts opts = {.root_dir = STATIC_DIR};
mg_http_serve_file(c, hm, "./static/xterm.js", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm.css"), nullptr)) {
// xterm.css
struct mg_http_serve_opts opts = {.root_dir = STATIC_DIR};
mg_http_serve_file(c, hm, "./static/xterm.css", &opts);
} else if (mg_match(hm->uri, mg_str("/xterm-addon-fit.js"), nullptr)) {
// xterm-addon-fit.js
struct mg_http_serve_opts opts = {.root_dir = STATIC_DIR};
mg_http_serve_file(c, hm, "./static/xterm-addon-fit.js", &opts);
} else {
mg_http_reply(c, 404, "Content-Type: text/plain\r\n", "Not Found");
}
} else if (ev == MG_EV_WS_OPEN) {
// WebSocket соединение установлено
printf("WebSocket connection opened\n");
struct client_data *cd = (struct client_data *)c->fn_data;
if (cd) {
mg_ws_send(c, "Terminal ready - type 'exit' to restart session\r\n", 49,
WEBSOCKET_OP_TEXT);
}
} else if (ev == MG_EV_WS_MSG) {
// Сообщение от WebSocket клиента
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
struct client_data *cd = (struct client_data *)c->fn_data;
handle_websocket_message(c, wm, cd);
} else if (ev == MG_EV_CLOSE) {
// Закрытие соединения
struct client_data *cd = (struct client_data *)c->fn_data;
if (cd) {
printf("WebSocket connection closed, cleaning up...\n");
destroy_terminal_session(&cd->term);
free(cd);
c->fn_data = NULL;
}
} else if (ev == MG_EV_POLL) {
// Проверяем данные от терминала и отправляем через WebSocket
struct mg_connection *conn;
for (conn = mgr.conns; conn != NULL; conn = conn->next) {
if (!conn->is_websocket)
continue;
struct client_data *cd = (struct client_data *)conn->fn_data;
if (cd && cd->terminal_ready) {
// Проверяем, не завершился ли процесс
if (!is_process_alive(cd->term.child_pid)) {
printf("Terminal process died, restarting...\n");
restart_terminal_session(conn, cd);
continue;
}
// Читаем данные из терминала
char buffer[1024];
ssize_t bytes_read =
read_from_terminal(&cd->term, buffer, sizeof(buffer));
if (bytes_read > 0) {
mg_ws_send(conn, buffer, bytes_read, WEBSOCKET_OP_BINARY);
} else if (bytes_read == 0) {
// EOF - процесс завершился
printf("EOF from terminal, restarting...\n");
restart_terminal_session(conn, cd);
} else if (bytes_read < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
// Ошибка чтения
printf("Error reading from terminal: %s\n", strerror(errno));
restart_terminal_session(conn, cd);
}
}
}
}
}
// Обработчик сигналов для graceful shutdown
static void signal_handler(int sig) {
printf("\nShutting down server...\n");
// Очищаем все соединения
struct mg_connection *conn;
for (conn = mgr.conns; conn != NULL; conn = conn->next) {
if (conn->fn_data) {
struct client_data *cd = (struct client_data *)conn->fn_data;
destroy_terminal_session(&cd->term);
free(cd);
conn->fn_data = NULL;
}
printf("\nShutting down server...\n");
// Очищаем все соединения
struct mg_connection *conn;
for (conn = mgr.conns; conn != NULL; conn = conn->next) {
if (conn->fn_data) {
struct client_data *cd = (struct client_data *)conn->fn_data;
destroy_terminal_session(&cd->term);
free(cd);
conn->fn_data = NULL;
}
mg_mgr_free(&mgr);
exit(0);
}
mg_mgr_free(&mgr);
exit(0);
}
// Проверяем существование директории
static bool directory_exists(const char *path) {
struct stat st;
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
struct stat st;
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}
int main(void) {
// Устанавливаем обработчики сигналов
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// Инициализируем менеджер соединений
mg_mgr_init(&mgr);
printf("Mongoose version: %s\n", MG_VERSION);
// Проверяем существование статической директории
if (!directory_exists(STATIC_DIR)) {
fprintf(stderr, "Static directory '%s' not found! Creating it...\n", STATIC_DIR);
if (mkdir(STATIC_DIR, 0755) != 0) {
fprintf(stderr, "Failed to create static directory\n");
return 1;
}
// Устанавливаем обработчики сигналов
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// Инициализируем менеджер соединений
mg_mgr_init(&mgr);
printf("Mongoose version: %s\n", MG_VERSION);
// Проверяем существование статической директории
if (!directory_exists(STATIC_DIR)) {
fprintf(stderr, "Static directory '%s' not found! Creating it...\n",
STATIC_DIR);
if (mkdir(STATIC_DIR, 0755) != 0) {
fprintf(stderr, "Failed to create static directory\n");
return 1;
}
// Создаем HTTP сервер
struct mg_connection *c = mg_http_listen(&mgr, s_http_addr, fn, NULL);
if (c == NULL) {
fprintf(stderr, "Failed to start server on %s\n", s_http_addr);
return 1;
}
printf("Starting web terminal server on %s\n", s_http_addr);
printf("Static files directory: %s\n", STATIC_DIR);
printf("Server is ready. Open http://localhost:8000 in your browser\n");
// Основной цикл
while (true) {
mg_mgr_poll(&mgr, 50); // 50ms timeout
}
mg_mgr_free(&mgr);
return 0;
}
// Создаем HTTP сервер
struct mg_connection *c = mg_http_listen(&mgr, s_http_addr, fn, NULL);
if (c == NULL) {
fprintf(stderr, "Failed to start server on %s\n", s_http_addr);
return 1;
}
printf("Starting web terminal server on %s\n", s_http_addr);
printf("Static files directory: %s\n", STATIC_DIR);
printf("Server is ready. Open http://localhost:8000 in your browser\n");
// Основной цикл
while (true) {
mg_mgr_poll(&mgr, 50); // 50ms timeout
}
mg_mgr_free(&mgr);
return 0;
}
+18 -18
View File
@@ -16361,7 +16361,7 @@ int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t
#define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro))
#endif
//
//
#if (MG_UECC_WORD_SIZE == 1)
#if MG_UECC_SUPPORTS_secp160r1
@@ -20899,7 +20899,7 @@ static bool cyw_wifi_connect(char *ssid, char *pass) {
uint32_t data[64/4 + 1]; // max pass length: 64 for WPA, 128 for WPA3 SAE
uint16_t *da = (uint16_t *) data;
unsigned int len;
uint32_t val;
uint32_t val;
val = 4; // security type: 0 for none, 2 for WPA, 4 for WPA2/WPA3, 6 for mixed WPA/WPA2
// sup_wpa[1] = 0 if not using security
if (!(cyw_ioctl_set(134 /* SET_WSEC */, (uint8_t *)&val, sizeof(val))
@@ -20941,7 +20941,7 @@ static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
uint32_t data[64/4 + 2]; // max pass length: 64 for WPA, 128 for WPA3 SAE
uint16_t *da = (uint16_t *) data;
unsigned int len;
uint32_t val;
uint32_t val;
// CHIP DEPENDENCY
// RPi set the AMPDU parameter for AP (window size = 2) *****************
// val = 2 ; cyw_ioctl_iovar_set_(0, "ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
@@ -20970,10 +20970,10 @@ static bool cyw_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
da[1] = 1; // indicates wireless security key, skip for WPA3 SAE
memcpy((uint8_t *)data + 2 * sizeof(uint16_t), pass, len); // skip for WPA3 SAE
if (!cyw_ioctl_set_(1, 268 /* SET_WSEC_PMK */, data, sizeof(data))) return false; // skip for WPA3 SAE, sizeof/2 if supporting SAE but using WPA
/* for WPA3 SAE:
/* for WPA3 SAE:
memcpy((uint8_t *)data + sizeof(uint16_t), pass, len);
cyw_ioctl_iovar_set_(1, "sae_password", data, sizeof(data)); */
/* for WPA3 or mixed WPA2/WPA3:
/* for WPA3 or mixed WPA2/WPA3:
val = 5 ; cyw_ioctl_iovar_set_(1, "sae_max_pwe_loop", (uint8_t *)&val, sizeof(val)); // Some chipsets do not support this */
// resume if not using auth
@@ -21119,7 +21119,7 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
bss.band = band & CYW_BSS_BAND2G ? MG_WIFI_BAND_2G : MG_WIFI_BAND_5G;
bss.security = (sbss->capability & MG_BIT(4) /* CAP_PRIVACY */) ? MG_WIFI_SECURITY_WEP : MG_WIFI_SECURITY_OPEN;
{ // travel IEs (Information Elements) in search of security definitions
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
const uint8_t wot1[4] = {0x00, 0x50, 0xf2, 0x01}; // WPA_OUI_TYPE1
uint8_t *ie = (uint8_t *)sbss + sbss->ie_offset;
int bytes = (int) sbss->ie_length;
while (bytes > 0 && ie[1] + 2 < bytes) { // ie[0] -> type, ie[1] -> bytes from ie[2]
@@ -21130,11 +21130,11 @@ static void cyw_handle_scan_result(uint32_t status, struct scan_result *data, si
bytes -= ie[1] + 2;
}
}
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf, bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI, bss.security));
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
} else {
MG_ERROR(("scan error"));
}
}
}
// clang-format on
@@ -21326,7 +21326,7 @@ static bool cyw_init(uint8_t *mac) {
// CHIP DEPENDENCY
val = 8 ; cyw_ioctl_iovar_set("ampdu_ba_wsize", (uint8_t *)&val, sizeof(val));
val = 4 ; cyw_ioctl_iovar_set("ampdu_mpdu", (uint8_t *)&val, sizeof(val));
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
val = 0 /* 8K */; cyw_ioctl_iovar_set("ampdu_rx_factor", (uint8_t *)&val, sizeof(val));
//
{
struct cyw_country c;
@@ -21544,7 +21544,7 @@ static bool cyw_load_fwll(void *fwdata, size_t fwlen, void *nvramdata, size_t nv
cyw_load_data(CYW_CHIP_ATCMRAM_BASE, fwdata, fwlen);
mg_delayms(5); // TODO(scaprile): CHECK IF THIS IS ACTUALLY NEEDED
// Load NVRAM and place 'length ~length' at the end; end of chip RAM
{
{
const uint32_t start = CYW_CHIP_RAM_SIZE - 4 - nvramlen;
cyw_load_data(start, nvramdata, nvramlen); // nvramlen must be a multiple of 4
// RAM_SIZE is a multiple of WINSZ, so the place for len ~len will be at the end of the window
@@ -21835,7 +21835,7 @@ static bool cyw_sdio_init() {
struct mg_tcpip_sdio *s = (struct mg_tcpip_sdio *) d->bus;
uint32_t val = 0;
if (!mg_sdio_init(s)) return false;
// no block transfers on F0. if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_BUS, 32)) return false;
// no block transfers on F0. if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_BUS, 32)) return false;
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_CHIP, 64)) return false;
if (!mg_sdio_set_blksz(s, CYW_SDIO_FUNC_WLAN, 64)) return false;
// TODO(scaprile): we don't handle SDIO interrupts, study CCCR INTEN and SDIO support (SDIO 6.3, 8)
@@ -22052,7 +22052,7 @@ static bool mg_tcpip_driver_imxrt_init(struct mg_tcpip_if *ifp) {
int cr = (d == NULL || d->mdc_cr < 0) ? 24 : d->mdc_cr;
ENET->MSCR = (1 << 8) | ((cr & 0x3f) << 1); // HOLDTIME 2 clks
struct mg_phy phy = {enet_read_phy, enet_write_phy};
mg_phy_init(&phy, d->phy_addr, MG_PHY_LEDS_ACTIVE_HIGH); // MAC clocks PHY
mg_phy_init(&phy, d->phy_addr, MG_PHY_LEDS_ACTIVE_HIGH); // MAC clocks PHY
// Select RMII mode, 100M, keep CRC, set max rx length, disable loop
ENET->RCR = (1518 << 16) | MG_BIT(8) | MG_BIT(2);
// ENET->RCR |= MG_BIT(3); // Receive all
@@ -24551,13 +24551,13 @@ struct tms570_mdio {
#define ETH_PKT_SIZE 1540 // Max frame size
#define ETH_DESC_CNT 4 // Descriptors count
#define ETH_DS 4 // Descriptor size (words)
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]
static uint32_t s_txdesc[ETH_DESC_CNT][ETH_DS]
__attribute__((section(".ETH_CPPI"), aligned(4))); // TX descriptors
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]
static uint32_t s_rxdesc[ETH_DESC_CNT][ETH_DS]
__attribute__((section(".ETH_CPPI"), aligned(4))); // RX descriptors
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]
static uint8_t s_rxbuf[ETH_DESC_CNT][ETH_PKT_SIZE]
__attribute__((aligned(4))); // RX ethernet buffers
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]
static uint8_t s_txbuf[ETH_DESC_CNT][ETH_PKT_SIZE]
__attribute__((aligned(4))); // TX ethernet buffers
static struct mg_tcpip_if *s_ifp; // MIP interface
static uint16_t emac_read_phy(uint8_t addr, uint8_t reg) {
@@ -24638,7 +24638,7 @@ static bool mg_tcpip_driver_tms570_init(struct mg_tcpip_if *ifp) {
}
s_txdesc[ETH_DESC_CNT - 1][0] = 0;
s_rxdesc[ETH_DESC_CNT - 1][0] = 0;
EMAC->MACCONTROL = MG_BIT(5) | MG_BIT(0); // Enable MII, Full-duplex
//EMAC->TXINTMASKSET = 1; // Enable TX interrupt
EMAC->RXINTMASKSET = 1; // Enable RX interrupt
@@ -24665,7 +24665,7 @@ static size_t mg_tcpip_driver_tms570_tx(const void *buf, size_t len,
s_txdesc[s_txno][2] = SWAP32((uint32_t) len); // Set data len
s_txdesc[s_txno][3] =
SWAP32(MG_BIT(31) | MG_BIT(30) | MG_BIT(29) | len); // SOP, EOP, OWN, length
while(EMAC->TXHDP[0] != 0) (void) 0;
EMAC->TXHDP[0] = (uint32_t) &s_txdesc[s_txno][0];
if(++s_txno == ETH_DESC_CNT) {
+757 -929
View File
File diff suppressed because it is too large Load Diff
+142 -142
View File
@@ -1,158 +1,158 @@
#include "terminal.h"
#include <errno.h>
#include <fcntl.h>
#include <pty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <pty.h>
#include <unistd.h>
#include <utmp.h>
#include <signal.h>
#include <errno.h>
int create_terminal_session(struct terminal_session *session, const char *shell) {
// Создаем pty
int master, slave;
char slave_name[64];
if (openpty(&master, &slave, slave_name, NULL, NULL) == -1) {
perror("openpty failed");
return -1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
close(master);
close(slave);
return -1;
}
if (pid == 0) {
// Дочерний процесс
close(master);
// Устанавливаем pty как контролирующий терминал
setsid();
ioctl(slave, TIOCSCTTY, 1);
// Перенаправляем стандартные потоки
dup2(slave, STDIN_FILENO);
dup2(slave, STDOUT_FILENO);
dup2(slave, STDERR_FILENO);
if (slave > STDERR_FILENO) {
close(slave);
}
// Устанавливаем переменные окружения
setenv("TERM", "xterm-256color", 1);
setenv("COLORTERM", "truecolor", 1);
// Запускаем shell
execlp(shell, shell, NULL);
// Если execlp вернулся, значит произошла ошибка
perror("execlp failed");
exit(EXIT_FAILURE);
}
// Родительский процесс
int create_terminal_session(struct terminal_session *session,
const char *shell) {
// Создаем pty
int master, slave;
char slave_name[64];
if (openpty(&master, &slave, slave_name, NULL, NULL) == -1) {
perror("openpty failed");
return -1;
}
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
close(master);
close(slave);
session->master_pty = master;
session->slave_pty = slave;
session->child_pid = pid;
session->active = true;
// Устанавливаем неблокирующий режим
int flags = fcntl(master, F_GETFL, 0);
fcntl(master, F_SETFL, flags | O_NONBLOCK);
printf("Created terminal session with PID %d\n", pid);
return 0;
return -1;
}
if (pid == 0) {
// Дочерний процесс
close(master);
// Устанавливаем pty как контролирующий терминал
setsid();
ioctl(slave, TIOCSCTTY, 1);
// Перенаправляем стандартные потоки
dup2(slave, STDIN_FILENO);
dup2(slave, STDOUT_FILENO);
dup2(slave, STDERR_FILENO);
if (slave > STDERR_FILENO) {
close(slave);
}
// Устанавливаем переменные окружения
setenv("TERM", "xterm-256color", 1);
setenv("COLORTERM", "truecolor", 1);
// Запускаем shell
execlp(shell, shell, NULL);
// Если execlp вернулся, значит произошла ошибка
perror("execlp failed");
exit(EXIT_FAILURE);
}
// Родительский процесс
close(slave);
session->master_pty = master;
session->slave_pty = slave;
session->child_pid = pid;
session->active = true;
// Устанавливаем неблокирующий режим
int flags = fcntl(master, F_GETFL, 0);
fcntl(master, F_SETFL, flags | O_NONBLOCK);
printf("Created terminal session with PID %d\n", pid);
return 0;
}
void destroy_terminal_session(struct terminal_session *session) {
if (!session || !session->active) {
return;
}
printf("Destroying terminal session with PID %d\n", session->child_pid);
// Завершаем дочерний процесс
if (session->child_pid > 0) {
// Отправляем SIGKILL
int status;
kill(session->child_pid, SIGKILL);
waitpid(session->child_pid, &status, 0);
}
// Закрываем pty
if (session->master_pty != -1) {
close(session->master_pty);
session->master_pty = -1;
}
session->active = false;
session->child_pid = 0;
printf("Terminal session destroyed\n");
if (!session || !session->active) {
return;
}
printf("Destroying terminal session with PID %d\n", session->child_pid);
// Завершаем дочерний процесс
if (session->child_pid > 0) {
// Отправляем SIGKILL
int status;
kill(session->child_pid, SIGKILL);
waitpid(session->child_pid, &status, 0);
}
// Закрываем pty
if (session->master_pty != -1) {
close(session->master_pty);
session->master_pty = -1;
}
session->active = false;
session->child_pid = 0;
printf("Terminal session destroyed\n");
}
ssize_t read_from_terminal(struct terminal_session *session, char *buffer, size_t size) {
if (!session || !session->active) {
return -1;
}
ssize_t bytes_read = read(session->master_pty, buffer, size - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
} else if (bytes_read == 0) {
// EOF - соединение закрыто
return 0;
} else if (bytes_read < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("read from terminal failed");
return -1;
}
// Нет данных для чтения - это нормально в неблокирующем режиме
return -2;
}
return bytes_read;
}
ssize_t read_from_terminal(struct terminal_session *session, char *buffer,
size_t size) {
if (!session || !session->active) {
return -1;
}
ssize_t write_to_terminal(struct terminal_session *session, const char *data, size_t size) {
if (!session || !session->active) {
return -1;
}
ssize_t bytes_written = write(session->master_pty, data, size);
if (bytes_written < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
perror("write to terminal failed");
return -1;
}
return bytes_written;
}
int resize_terminal(struct terminal_session *session, uint16_t rows, uint16_t cols) {
if (!session || !session->active) {
return -1;
}
struct winsize ws = {
.ws_row = rows,
.ws_col = cols,
.ws_xpixel = 0,
.ws_ypixel = 0
};
if (ioctl(session->master_pty, TIOCSWINSZ, &ws) == -1) {
perror("ioctl TIOCSWINSZ failed");
return -1;
}
ssize_t bytes_read = read(session->master_pty, buffer, size - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
} else if (bytes_read == 0) {
// EOF - соединение закрыто
return 0;
}
} else if (bytes_read < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("read from terminal failed");
return -1;
}
// Нет данных для чтения - это нормально в неблокирующем режиме
return -2;
}
return bytes_read;
}
ssize_t write_to_terminal(struct terminal_session *session, const char *data,
size_t size) {
if (!session || !session->active) {
return -1;
}
ssize_t bytes_written = write(session->master_pty, data, size);
if (bytes_written < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
perror("write to terminal failed");
return -1;
}
return bytes_written;
}
int resize_terminal(struct terminal_session *session, uint16_t rows,
uint16_t cols) {
if (!session || !session->active) {
return -1;
}
struct winsize ws = {
.ws_row = rows, .ws_col = cols, .ws_xpixel = 0, .ws_ypixel = 0};
if (ioctl(session->master_pty, TIOCSWINSZ, &ws) == -1) {
perror("ioctl TIOCSWINSZ failed");
return -1;
}
return 0;
}
+14 -10
View File
@@ -1,25 +1,29 @@
#ifndef TERMINAL_H
#define TERMINAL_H
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
struct terminal_session {
int master_pty;
int slave_pty;
pid_t child_pid;
bool active;
int master_pty;
int slave_pty;
pid_t child_pid;
bool active;
};
// Функции для работы с терминалом
int create_terminal_session(struct terminal_session *session, const char *shell);
int create_terminal_session(struct terminal_session *session,
const char *shell);
void destroy_terminal_session(struct terminal_session *session);
ssize_t read_from_terminal(struct terminal_session *session, char *buffer, size_t size);
ssize_t write_to_terminal(struct terminal_session *session, const char *data, size_t size);
int resize_terminal(struct terminal_session *session, uint16_t rows, uint16_t cols);
ssize_t read_from_terminal(struct terminal_session *session, char *buffer,
size_t size);
ssize_t write_to_terminal(struct terminal_session *session, const char *data,
size_t size);
int resize_terminal(struct terminal_session *session, uint16_t rows,
uint16_t cols);
#endif
+187 -168
View File
@@ -1,176 +1,195 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<title>Web Terminal</title>
<link rel="stylesheet" href="xterm.css">
<style>
body {
margin: 0;
padding: 20px;
background-color: #1e1e1e;
color: #fff;
font-family: Arial, sans-serif;
height: 100vh;
display: flex;
flex-direction: column;
}
#terminal-container {
flex: 1;
border: 1px solid #333;
border-radius: 5px;
overflow: hidden;
margin-top: 10px;
}
.status {
padding: 10px;
border-radius: 3px;
font-weight: bold;
margin-bottom: 10px;
}
.connected { background-color: #2d5a2d; }
.disconnected { background-color: #5a2d2d; }
.connecting { background-color: #5a5a2d; }
</style>
</head>
<body>
<h1>Web Terminal</h1>
<div class="status connecting" id="status">Connecting...</div>
<div id="terminal-container"></div>
<head>
<title>Web Terminal</title>
<link rel="stylesheet" href="xterm.css" />
<style>
body {
margin: 0;
padding: 20px;
background-color: #1e1e1e;
color: #fff;
font-family: Arial, sans-serif;
height: 100vh;
display: flex;
flex-direction: column;
}
<script src="xterm.js"></script>
<script src="xterm-addon-fit.js"></script>
<script>
class WebTerminal {
constructor() {
this.terminal = new Terminal({
cursorBlink: true,
theme: {
background: '#000000',
foreground: '#ffffff',
cursor: '#ffffff'
}
});
this.fitAddon = new FitAddon.FitAddon();
this.terminal.loadAddon(this.fitAddon);
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 3000;
this.init();
#terminal-container {
flex: 1;
border: 1px solid #333;
border-radius: 5px;
overflow: hidden;
margin-top: 10px;
}
init() {
const terminalContainer = document.getElementById('terminal-container');
this.terminal.open(terminalContainer);
this.fitAddon.fit();
this.terminal.writeln('Welcome to Web Terminal');
this.terminal.writeln('Connecting to server...');
this.connect();
// Handle terminal input
this.terminal.onData((data) => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
});
// Handle resize
window.addEventListener('resize', () => {
this.fitAddon.fit();
this.sendResize();
});
// Handle page unload
window.addEventListener('beforeunload', () => {
if (this.ws) {
this.ws.close();
}
});
.status {
padding: 10px;
border-radius: 3px;
font-weight: bold;
margin-bottom: 10px;
}
connect() {
this.updateStatus('Connecting...', 'connecting');
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws`;
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log('WebSocket connected');
.connected {
background-color: #2d5a2d;
}
.disconnected {
background-color: #5a2d2d;
}
.connecting {
background-color: #5a5a2d;
}
</style>
</head>
<body>
<h1>Web Terminal</h1>
<div class="status connecting" id="status">Connecting...</div>
<div id="terminal-container"></div>
<script src="xterm.js"></script>
<script src="xterm-addon-fit.js"></script>
<script>
class WebTerminal {
constructor() {
this.terminal = new Terminal({
cursorBlink: true,
theme: {
background: "#000000",
foreground: "#ffffff",
cursor: "#ffffff",
},
});
this.fitAddon = new FitAddon.FitAddon();
this.terminal.loadAddon(this.fitAddon);
this.ws = null;
this.reconnectAttempts = 0;
this.updateStatus('Connected', 'connected');
this.terminal.clear();
this.sendResize();
};
this.ws.onmessage = (event) => {
if (typeof event.data === 'string') {
this.terminal.write(event.data);
} else {
// Handle binary data
const reader = new FileReader();
reader.onload = () => {
const data = new Uint8Array(reader.result);
this.terminal.write(data);
};
reader.readAsArrayBuffer(event.data);
}
};
this.ws.onclose = (event) => {
console.log('WebSocket disconnected:', event.code, event.reason);
this.updateStatus('Disconnected', 'disconnected');
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = this.reconnectDelay * this.reconnectAttempts;
this.terminal.write(`\r\nConnection lost. Reconnecting in ${delay/1000}s...\r\n`);
setTimeout(() => {
this.connect();
}, delay);
} else {
this.terminal.write('\r\nFailed to reconnect. Please refresh the page.\r\n');
}
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
this.updateStatus('Connection Error', 'disconnected');
};
}
sendResize() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const dimensions = this.terminal;
const resizeMsg = {
cols: dimensions.cols,
rows: dimensions.rows
this.maxReconnectAttempts = 5;
this.reconnectDelay = 3000;
this.init();
}
init() {
const terminalContainer =
document.getElementById("terminal-container");
this.terminal.open(terminalContainer);
this.fitAddon.fit();
this.terminal.writeln("Welcome to Web Terminal");
this.terminal.writeln("Connecting to server...");
this.connect();
// Handle terminal input
this.terminal.onData((data) => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(data);
}
});
// Handle resize
window.addEventListener("resize", () => {
this.fitAddon.fit();
this.sendResize();
});
// Handle page unload
window.addEventListener("beforeunload", () => {
if (this.ws) {
this.ws.close();
}
});
}
connect() {
this.updateStatus("Connecting...", "connecting");
const protocol =
window.location.protocol === "https:" ? "wss:" : "ws:";
const wsUrl = `${protocol}//${window.location.host}/ws`;
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log("WebSocket connected");
this.reconnectAttempts = 0;
this.updateStatus("Connected", "connected");
this.terminal.clear();
this.sendResize();
};
this.ws.send(JSON.stringify(resizeMsg));
this.ws.onmessage = (event) => {
if (typeof event.data === "string") {
this.terminal.write(event.data);
} else {
// Handle binary data
const reader = new FileReader();
reader.onload = () => {
const data = new Uint8Array(reader.result);
this.terminal.write(data);
};
reader.readAsArrayBuffer(event.data);
}
};
this.ws.onclose = (event) => {
console.log(
"WebSocket disconnected:",
event.code,
event.reason,
);
this.updateStatus("Disconnected", "disconnected");
if (
this.reconnectAttempts < this.maxReconnectAttempts
) {
this.reconnectAttempts++;
const delay =
this.reconnectDelay * this.reconnectAttempts;
this.terminal.write(
`\r\nConnection lost. Reconnecting in ${delay / 1000}s...\r\n`,
);
setTimeout(() => {
this.connect();
}, delay);
} else {
this.terminal.write(
"\r\nFailed to reconnect. Please refresh the page.\r\n",
);
}
};
this.ws.onerror = (error) => {
console.error("WebSocket error:", error);
this.updateStatus("Connection Error", "disconnected");
};
}
sendResize() {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
const dimensions = this.terminal;
const resizeMsg = {
cols: dimensions.cols,
rows: dimensions.rows,
};
this.ws.send(JSON.stringify(resizeMsg));
}
}
updateStatus(text, className) {
const status = document.getElementById("status");
status.textContent = text;
status.className = `status ${className}`;
}
}
updateStatus(text, className) {
const status = document.getElementById('status');
status.textContent = text;
status.className = `status ${className}`;
}
}
// Initialize terminal when page loads
document.addEventListener('DOMContentLoaded', () => {
new WebTerminal();
});
</script>
</body>
</html>
// Initialize terminal when page loads
document.addEventListener("DOMContentLoaded", () => {
new WebTerminal();
});
</script>
</body>
</html>
+73 -2
View File
@@ -1,2 +1,73 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));
//# sourceMappingURL=xterm-addon-fit.js.map
!(function (e, t) {
"object" == typeof exports && "object" == typeof module
? (module.exports = t())
: "function" == typeof define && define.amd
? define([], t)
: "object" == typeof exports
? (exports.FitAddon = t())
: (e.FitAddon = t());
})(self, () =>
(() => {
"use strict";
var e = {};
return (
(() => {
var t = e;
(Object.defineProperty(t, "__esModule", { value: !0 }),
(t.FitAddon = void 0),
(t.FitAddon = class {
activate(e) {
this._terminal = e;
}
dispose() {}
fit() {
const e = this.proposeDimensions();
if (!e || !this._terminal || isNaN(e.cols) || isNaN(e.rows))
return;
const t = this._terminal._core;
(this._terminal.rows === e.rows &&
this._terminal.cols === e.cols) ||
(t._renderService.clear(),
this._terminal.resize(e.cols, e.rows));
}
proposeDimensions() {
if (!this._terminal) return;
if (
!this._terminal.element ||
!this._terminal.element.parentElement
)
return;
const e = this._terminal._core,
t = e._renderService.dimensions;
if (0 === t.css.cell.width || 0 === t.css.cell.height) return;
const r =
0 === this._terminal.options.scrollback
? 0
: e.viewport.scrollBarWidth,
i = window.getComputedStyle(
this._terminal.element.parentElement,
),
o = parseInt(i.getPropertyValue("height")),
s = Math.max(0, parseInt(i.getPropertyValue("width"))),
n = window.getComputedStyle(this._terminal.element),
l =
o -
(parseInt(n.getPropertyValue("padding-top")) +
parseInt(n.getPropertyValue("padding-bottom"))),
a =
s -
(parseInt(n.getPropertyValue("padding-right")) +
parseInt(n.getPropertyValue("padding-left"))) -
r;
return {
cols: Math.max(2, Math.floor(a / t.css.cell.width)),
rows: Math.max(1, Math.floor(l / t.css.cell.height)),
};
}
}));
})(),
e
);
})(),
);
//# sourceMappingURL=xterm-addon-fit.js.map
+37 -15
View File
@@ -79,7 +79,7 @@
.xterm .composition-view {
/* TODO: Composition position got messed up somewhere */
background: #000;
color: #FFF;
color: #fff;
display: none;
position: absolute;
white-space: nowrap;
@@ -166,33 +166,55 @@
opacity: 1 !important;
}
.xterm-underline-1 { text-decoration: underline; }
.xterm-underline-2 { text-decoration: double underline; }
.xterm-underline-3 { text-decoration: wavy underline; }
.xterm-underline-4 { text-decoration: dotted underline; }
.xterm-underline-5 { text-decoration: dashed underline; }
.xterm-underline-1 {
text-decoration: underline;
}
.xterm-underline-2 {
text-decoration: double underline;
}
.xterm-underline-3 {
text-decoration: wavy underline;
}
.xterm-underline-4 {
text-decoration: dotted underline;
}
.xterm-underline-5 {
text-decoration: dashed underline;
}
.xterm-overline {
text-decoration: overline;
}
.xterm-overline.xterm-underline-1 { text-decoration: overline underline; }
.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; }
.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; }
.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; }
.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; }
.xterm-overline.xterm-underline-1 {
text-decoration: overline underline;
}
.xterm-overline.xterm-underline-2 {
text-decoration: overline double underline;
}
.xterm-overline.xterm-underline-3 {
text-decoration: overline wavy underline;
}
.xterm-overline.xterm-underline-4 {
text-decoration: overline dotted underline;
}
.xterm-overline.xterm-underline-5 {
text-decoration: overline dashed underline;
}
.xterm-strikethrough {
text-decoration: line-through;
}
.xterm-screen .xterm-decoration-container .xterm-decoration {
z-index: 6;
position: absolute;
z-index: 6;
position: absolute;
}
.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer {
z-index: 7;
.xterm-screen
.xterm-decoration-container
.xterm-decoration.xterm-decoration-top-layer {
z-index: 7;
}
.xterm-decoration-overview-ruler {
+14698 -2
View File
File diff suppressed because one or more lines are too long