Compare commits
No commits in common. "8cff69ced0ceb4d3f58d8a30461c24135c824346" and "fc336b661f8f5580c93262adc469c8cd38e98c4d" have entirely different histories.
8cff69ced0
...
fc336b661f
11 changed files with 644 additions and 466 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,3 +1,6 @@
|
|||
based
|
||||
fbc
|
||||
sfb
|
||||
sfb.log
|
||||
code
|
||||
*.o
|
||||
*.tar.gz
|
||||
|
|
28
Makefile
28
Makefile
|
@ -2,40 +2,40 @@
|
|||
.SUFFIXES:
|
||||
|
||||
VERSION = 1.0
|
||||
TARGET = based
|
||||
MANPAGE = $(TARGET).1
|
||||
TARGET = sfb
|
||||
TARGET2 = fbc
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR = $(PREFIX)/bin
|
||||
MANDIR = $(PREFIX)/share/man/man1
|
||||
|
||||
CFLAGS = -Os -march=native -mtune=native -pipe -s -std=c99 -pedantic -Wall
|
||||
CFLAGS = -Os -march=native -mtune=native -pipe -s -std=c99 -pedantic -Wall -D_XOPEN_SOURCE=600
|
||||
|
||||
SRC = based.c
|
||||
SRC = $(TARGET).c
|
||||
SRC2 = $(TARGET2).c
|
||||
|
||||
$(TARGET): $(SRC)
|
||||
$(CC) $(SRC) -o $@ $(CFLAGS)
|
||||
$(TARGET): $(SRC) $(SRC2)
|
||||
$(CC) $(SRC) -o $(TARGET) $(CFLAGS)
|
||||
$(CC) $(SRC2) -o $(TARGET2) $(CFLAGS)
|
||||
|
||||
dist:
|
||||
mkdir -p $(TARGET)-$(VERSION)
|
||||
cp -R README.md $(MANPAGE) $(TARGET) $(TARGET)-$(VERSION)
|
||||
cp -R README.md $(TARGET) $(TARGET2) $(TARGET)-$(VERSION)
|
||||
tar -cf $(TARGET)-$(VERSION).tar $(TARGET)-$(VERSION)
|
||||
gzip $(TARGET)-$(VERSION).tar
|
||||
rm -rf $(TARGET)-$(VERSION)
|
||||
|
||||
install: $(TARGET)
|
||||
install: $(TARGET) $(TARGET2)
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
mkdir -p $(DESTDIR)$(MANDIR)
|
||||
cp -p $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
cp -p $(TARGET) $(TARGET2) $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
cp -p $(MANPAGE) $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||
chmod 644 $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/$(TARGET2)
|
||||
|
||||
uninstall:
|
||||
rm $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||
rm $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||
rm $(DESTDIR)$(BINDIR)/$(TARGET2)
|
||||
|
||||
clean:
|
||||
rm $(TARGET)
|
||||
rm $(TARGET2)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
|
|
31
README.md
31
README.md
|
@ -1,25 +1,24 @@
|
|||
# based
|
||||
based is a command line tool to help A level students to revise base conversion.
|
||||
# sfb
|
||||
Suckless File Bin is a temporary file host, similar to [0x0.st](https://0x0.st) but is more minimal and simple. sfb is heavily inspired by [fiche](https://github.com/solusipse/fiche), it comes with a socket server(sfb) and socket client(fbc) that use a custom protocol(SFP, simple file protocol) which doesn't use HTTP to get around some VPS doesn't allow HTTP request to send files.
|
||||
|
||||
# Preview
|
||||

|
||||
`nginx.conf` has been provided so you can do reverse proxy.
|
||||
`index.html` can be used for just nginx or flask server.
|
||||
|
||||
Notice for SFP, nginx is assumed to be used as index.txt will be created for each file sent(file path: OUTPUTDIR/ID/index.txt). And you are not required to use nginx for the HTTP server. With HTTP, no index.txt will be created, instead just a raw file as it will be handled by the flask server.
|
||||
|
||||
# Usage
|
||||
```
|
||||
Usage: based -f [from] -t [to] -n [number]
|
||||
based is a command line tool to help A level students to revise base conversion.
|
||||
Options:
|
||||
-f [bin|oct|dec|hex] The base to convert from
|
||||
-t [bin|oct|dec|hex] The base to convert to
|
||||
-n [number] The number to convert (must be representable by 8 bits)
|
||||
When from base is binary, the number must have 8 characters
|
||||
When from base is octal, the number must have at most 3 characters
|
||||
When from base is hexadecimal, the number must have 2 characters
|
||||
When from base is decimal, the number must be a bigger than 0 and smaller than 256
|
||||
```sh
|
||||
sfb # SFP
|
||||
pbc # SFP
|
||||
python sfb.py # HTTP
|
||||
```
|
||||
|
||||
# Dependencies
|
||||
- For C Server:
|
||||
None
|
||||
- For Python HTTP server:
|
||||
+ flask
|
||||
+ flask-cors
|
||||
|
||||
# Building
|
||||
You will need to run these with elevated privilages.
|
||||
|
@ -32,4 +31,4 @@ $ make
|
|||
Contributions are welcomed, feel free to open a pull request.
|
||||
|
||||
# License
|
||||
This project is licensed under the GNU Public License v3.0. See [LICENSE](https://github.com/night0721/based/blob/master/LICENSE) for more information.
|
||||
This project is licensed under the GNU Public License v3.0. See [LICENSE](https://github.com/night0721/sfb/blob/master/LICENSE) for more information.
|
||||
|
|
48
based.1
48
based.1
|
@ -1,48 +0,0 @@
|
|||
.TH based 1 based\-VERSION
|
||||
.SH NAME
|
||||
based \- base conversion command line tool
|
||||
.SH SYNOPSIS
|
||||
.B based
|
||||
.RB [ \-f ]
|
||||
.RB [ \-t ]
|
||||
.RB [ \-n ]
|
||||
.RB [ \-h ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
based is a command line tool to help A level students to revise base conversion.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.B \-f [bin|oct|dec|hex]
|
||||
Set the base of the number you want to convert from.
|
||||
|
||||
.TP
|
||||
.B \-t [bin|oct|dec|hex]
|
||||
Set the base of the number you want to convert to.
|
||||
|
||||
.TP
|
||||
.B \-n
|
||||
Set the number you want to convert.
|
||||
|
||||
.TP
|
||||
.B \-h
|
||||
Show help message.
|
||||
|
||||
.SH EXAMPLES
|
||||
To convert the number 00001010 from binary to decimal, you can use the following command:
|
||||
.PP
|
||||
.B based \-f bin \-t dec \-n 00001010
|
||||
.PP
|
||||
To convert the number 12 from decimal to binary, you can use the following command:
|
||||
.PP
|
||||
.B based \-f dec \-t bin \-n 12
|
||||
.PP
|
||||
To convert the number 12 from decimal to octal, you can use the following command:
|
||||
.PP
|
||||
.B based \-f dec \-t oct \-n 12
|
||||
.PP
|
||||
|
||||
.SH AUTHOR
|
||||
Made by Night Kaly
|
||||
.B <night@night0721.xyz>
|
387
based.c
387
based.c
|
@ -1,387 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void bin_to_oct(char *binary) {
|
||||
printf("Converting Binary to Octal:\n");
|
||||
printf("First draw a table with 3 columns and list the index of 4, 2, 1.\n");
|
||||
printf("2 1 | 4 2 1 | 4 2 1\n");
|
||||
printf("Fill in the table with the binary number.\n");
|
||||
printf("2 1 | 4 2 1 | 4 2 1\n");
|
||||
printf("%c %c | %c %c %c | %c %c %c\n", binary[0], binary[1], binary[2], binary[3], binary[4], binary[5], binary[6], binary[7]);
|
||||
printf("Convert each row to octal.\n");
|
||||
char *first_col = malloc(sizeof(char) * 3);
|
||||
char *second_col = malloc(sizeof(char) * 3);
|
||||
char *third_col = malloc(sizeof(char) * 3);
|
||||
strncpy(first_col, binary, 3);
|
||||
first_col[2] = '\0';
|
||||
strncpy(second_col, binary + 2, 3);
|
||||
second_col[3] = '\0';
|
||||
strncpy(third_col, binary + 5, 3);
|
||||
third_col[3] = '\0';
|
||||
printf("%o %o %o\n", (unsigned int) strtol(first_col, NULL, 2), (unsigned int) strtol(second_col, NULL, 2), (unsigned int) strtol(third_col, NULL, 2));
|
||||
printf("Then, combine the octal numbers.\n");
|
||||
printf("%o\n", (unsigned int) strtol(binary, NULL, 2));
|
||||
}
|
||||
|
||||
void bin_to_dec(char *binary) {
|
||||
printf("Converting Binary to Decimal:\n");
|
||||
printf("List the Binary numbers out:\n");
|
||||
printf("128 64 32 16 8 4 2 1\n");
|
||||
printf("List the binary number.\n");
|
||||
printf("128 64 32 16 8 4 2 1\n");
|
||||
printf("%c %c %c %c %c %c %c %c\n", binary[0], binary[1], binary[2], binary[3], binary[4], binary[5], binary[6], binary[7]);
|
||||
printf("Add the columns with 1.\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (binary[i] == '1') {
|
||||
printf("%d", 1 << (7 - i));
|
||||
if (i < 7 ){
|
||||
for (int j = i; j < 7; j++) {
|
||||
// if all bits at the right are 0, don't print + sign
|
||||
if (binary[j + 1] == '1') {
|
||||
printf(" + ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf(" = \n%d\n", (unsigned int) strtol(binary, NULL, 2));
|
||||
}
|
||||
|
||||
void bin_to_hex(char *binary) {
|
||||
printf("Converting Binary to Hexadecimal:\n");
|
||||
printf("Split all bits into nibbles.\n");
|
||||
printf("8 4 2 1 | 8 4 2 1\n");
|
||||
printf("%c %c %c %c | %c %c %c %c\n", binary[0], binary[1], binary[2], binary[3], binary[4], binary[5], binary[6], binary[7]);
|
||||
char *nibble1 = malloc(sizeof(char) * 5);
|
||||
char *nibble2 = malloc(sizeof(char) * 5);
|
||||
strncpy(nibble1, binary, 4);
|
||||
nibble1[4] = '\0';
|
||||
strncpy(nibble2, binary + 4, 4);
|
||||
nibble2[4] = '\0';
|
||||
printf("Convert each nibble to hexadecimal.\n");
|
||||
printf("%X %X\n", (unsigned int) strtol(nibble1, NULL, 2), (unsigned int) strtol(nibble2, NULL, 2));
|
||||
printf("Then, combine the hexadecimal numbers.\n");
|
||||
printf("%X\n", (unsigned int) strtol(binary, NULL, 2));
|
||||
}
|
||||
|
||||
char* oct_to_bin(char *octal) {
|
||||
char *octal_copy = malloc(sizeof(char) * 4);
|
||||
strncpy(octal_copy, octal, 3);
|
||||
octal_copy[3] = '\0';
|
||||
int octal_copy2[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
octal_copy2[i] = octal[i] - '0';
|
||||
}
|
||||
char res[9];
|
||||
printf("Converting Octal to Binary:\n");
|
||||
printf("First draw a table with 3 columns and list the index of 4, 2, 1.\n");
|
||||
printf("2 1 | 4 2 1 | 4 2 1\n");
|
||||
printf("For each octal digit, convert it to binary by substracting the index.\n");
|
||||
printf("For first octal digit:\n");
|
||||
printf("%c -> ", octal[0]);
|
||||
int rows[3] = { 4, 2, 1 };
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (octal_copy2[0] - rows[i] >= 0) {
|
||||
printf("1");
|
||||
res[i - 1] = '1';
|
||||
octal_copy2[0] -= rows[i];
|
||||
} else {
|
||||
printf("0");
|
||||
res[i - 1] = '0';
|
||||
}
|
||||
}
|
||||
printf("\nFor second octal digit:\n");
|
||||
printf("%c -> ", octal[1]);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (octal_copy2[1] - rows[i] >= 0) {
|
||||
printf("1");
|
||||
res[i + 2] = '1';
|
||||
octal_copy2[1] -= rows[i];
|
||||
} else {
|
||||
printf("0");
|
||||
res[i + 2] = '0';
|
||||
}
|
||||
}
|
||||
printf("\nFor third octal digit:\n");
|
||||
printf("%c -> ", octal[2]);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (octal_copy2[2] - rows[i] >= 0) {
|
||||
printf("1");
|
||||
res[i + 5] = '1';
|
||||
octal_copy2[2] -= rows[i];
|
||||
} else {
|
||||
printf("0");
|
||||
res[i + 5] = '0';
|
||||
}
|
||||
}
|
||||
printf("\nThen, combine the binary numbers.\n");
|
||||
res[8] = '\0';
|
||||
printf("%s\n", res);
|
||||
char *result = malloc(sizeof(char) * 9);
|
||||
strncpy(result, res, 8);
|
||||
result[8] = '\0';
|
||||
return result;
|
||||
}
|
||||
|
||||
void oct_to_dec(char *octal) {
|
||||
printf("Converting Octal to Decimal:\n");
|
||||
printf("In order to convert octal to decimal, we need to convert octal to binary first.\n");
|
||||
char *res = oct_to_bin(octal);
|
||||
bin_to_dec(res);
|
||||
}
|
||||
|
||||
void oct_to_hex(char *octal) {
|
||||
printf("Converting Octal to Hexadecimal:\n");
|
||||
printf("In order to convert octal to hexadecimal, we need to convert octal to binary first.\n");
|
||||
char *res = oct_to_bin(octal);
|
||||
bin_to_hex(res);
|
||||
}
|
||||
|
||||
char *dec_to_bin(char *decimal) {
|
||||
printf("Converting Decimal to Binary:\n");
|
||||
printf("List the Binary numbers out:\n");
|
||||
printf("128 64 32 16 8 4 2 1\n");
|
||||
printf("One by one from left to right, subtract the number with the binary number if it is big enough to do so. If it is able to subtract, subtract it and place 1 in the table, else place 0\n");
|
||||
int dec = atoi(decimal);
|
||||
int dec_copy = dec;
|
||||
printf("\n%d", dec_copy);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (dec_copy - (1 << (7 - i)) >= 0) {
|
||||
printf(" - %d", 1 << (7 - i));
|
||||
dec_copy -= (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
printf(" = 0\n");
|
||||
char res[9];
|
||||
printf("128 64 32 16 8 4 2 1\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (dec - (1 << (7 - i)) >= 0) {
|
||||
printf("1 ");
|
||||
res[i] = '1';
|
||||
dec -= (1 << (7 - i));
|
||||
} else {
|
||||
printf("0 ");
|
||||
res[i] = '0';
|
||||
}
|
||||
}
|
||||
printf("\nAfter the subtraction, the binary number is: %s\n", res);
|
||||
char *res_copy = malloc(sizeof(char) * 9);
|
||||
strncpy(res_copy, res, 8);
|
||||
res_copy[8] = '\0';
|
||||
return res_copy;
|
||||
}
|
||||
|
||||
void dec_to_oct(char *decimal) {
|
||||
printf("Converting Decimal to Octal:\n");
|
||||
printf("In order to convert decimal to octal, we need to convert decimal to binary first.\n");
|
||||
char *res = dec_to_bin(decimal);
|
||||
printf("Then, convert the binary number to octal.\n");
|
||||
bin_to_oct(res);
|
||||
}
|
||||
|
||||
void dec_to_hex(char *decimal) {
|
||||
printf("Converting Decimal to Hexadecimal:\n");
|
||||
printf("Divide the decimal number by 16 take the quotient to be first digit of the hexadecimal number.\n");
|
||||
printf("Take the remainder to be the second digit of the hexadecimal number.\n");
|
||||
int dec = atoi(decimal);
|
||||
printf("%d / 16 = %d remainder %d\n", dec, dec / 16, dec % 16);
|
||||
printf("Then, convert the quotient and remainder to hexadecimal.\n");
|
||||
printf("%d -> %X\n", dec / 16, dec / 16);
|
||||
printf("%d -> %X\n", dec % 16, dec % 16);
|
||||
printf("Then, combine the hexadecimal numbers.\n");
|
||||
printf("%X%X\n", dec / 16, dec % 16);
|
||||
}
|
||||
|
||||
char *hex_to_bin(char *hexadecimal) {
|
||||
printf("Converting Hexadecimal to Binary:\n");
|
||||
printf("Split the hexadecimal number into 2 characters.\n");
|
||||
int char1 = hexadecimal[0] - '0';
|
||||
int char2 = hexadecimal[1] - '0';
|
||||
hexadecimal[0] = toupper(hexadecimal[0]);
|
||||
hexadecimal[1] = toupper(hexadecimal[1]);
|
||||
if (hexadecimal[0] >= 'A' && hexadecimal[0] <= 'F') {
|
||||
char1 = hexadecimal[0] - 'A' + 10;
|
||||
}
|
||||
if (hexadecimal[1] >= 'A' && hexadecimal[1] <= 'F') {
|
||||
char2 = hexadecimal[1] - 'A' + 10;
|
||||
}
|
||||
printf("%X %X\n", char1, char2);
|
||||
printf("Convert each character to nibble.\n");
|
||||
printf("For each character, subtract the number with the binary number if it is big enough to do so. If it is able to subtract, subtract it and place 1 in the table, else place 0.\n");
|
||||
printf("List the Binary numbers out:\n");
|
||||
printf("8 4 2 1 | 8 4 2 1\n");
|
||||
char *res = malloc(sizeof(char) * 9);
|
||||
printf("\nFirst character (%X):\n", char1);
|
||||
printf("%X", char1);
|
||||
int char1_copy = char1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (char1 - (1 << (3 - i)) >= 0) {
|
||||
printf(" - %d", 1 << (3 - i));
|
||||
char1 -= (1 << (3 - i));
|
||||
}
|
||||
}
|
||||
printf(" = 0\n");
|
||||
printf("8 4 2 1\n");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (char1_copy - (1 << (3 - i)) >= 0) {
|
||||
printf("1 ");
|
||||
res[i] = '1';
|
||||
char1_copy -= (1 << (3 - i));
|
||||
} else {
|
||||
printf("0 ");
|
||||
res[i] = '0';
|
||||
}
|
||||
}
|
||||
printf("\nSecond character (%X):\n", char2);
|
||||
printf("%X", char2);
|
||||
int char2_copy = char2;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (char2 - (1 << (3 - i)) >= 0) {
|
||||
printf(" - %d", 1 << (3 - i));
|
||||
char2 -= (1 << (3 - i));
|
||||
}
|
||||
}
|
||||
printf(" = 0\n");
|
||||
printf("8 4 2 1\n");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (char2_copy - (1 << (3 - i)) >= 0) {
|
||||
printf("1 ");
|
||||
res[i + 4] = '1';
|
||||
char2_copy -= (1 << (3 - i));
|
||||
} else {
|
||||
printf("0 ");
|
||||
res[i + 4] = '0';
|
||||
}
|
||||
}
|
||||
res[8] = '\0';
|
||||
printf("\nCombine the binary numbers.\n");
|
||||
printf("%s\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void hex_to_oct(char *hexadecimal) {
|
||||
printf("Converting Hexadecimal to Octal:\n");
|
||||
printf("In order to convert hexadecimal to octal, we need to convert hexadecimal to binary first.\n");
|
||||
char *res = hex_to_bin(hexadecimal);
|
||||
printf("Then, convert the binary number to octal.\n");
|
||||
bin_to_oct(res);
|
||||
}
|
||||
|
||||
void hex_to_dec(char *hexadecimal) {
|
||||
printf("Converting Hexadecimal to Decimal:\n");
|
||||
printf("In order to convert hexadecimal to decimal, we need to convert hexadecimal to binary first.\n");
|
||||
char *res = hex_to_bin(hexadecimal);
|
||||
printf("Then, convert the binary number to decimal.\n");
|
||||
bin_to_dec(res);
|
||||
}
|
||||
|
||||
void usage(char **argv) {
|
||||
printf("Usage: ./based -f [from] -t [to] -n [number]\n");
|
||||
}
|
||||
|
||||
void validate_input(char **argv, char *choices[4]) {
|
||||
if (strncmp(argv[1], "-f", 2) || strncmp(argv[3], "-t", 2) || strncmp(argv[5], "-n", 2)) {
|
||||
// option not in right place
|
||||
usage(argv);
|
||||
}
|
||||
// input validation
|
||||
for (int i = 2; i < 6; i += 2) {
|
||||
int found = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (strcmp(argv[i], choices[j]) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
printf("based: Unknown base -> %s\n", argv[i]);
|
||||
usage(argv);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 7) {
|
||||
if (argc == 2 && strncmp(argv[1], "-h", 2) == 0) {
|
||||
usage(argv);
|
||||
printf("based is a command line tool to help A level students to revise base conversion.\n");
|
||||
printf("Options:\n");
|
||||
printf(" -f [bin|oct|dec|hex] The base to convert from\n");
|
||||
printf(" -t [bin|oct|dec|hex] The base to convert to\n");
|
||||
printf(" -n [number] The number to convert (must be representable by 8 bits)\n");
|
||||
printf(" When from base is binary, the number must have 8 characters\n");
|
||||
printf(" When from base is octal, the number must have at most 3 characters\n");
|
||||
printf(" When from base is hexadecimal, the number must have 2 characters\n");
|
||||
printf(" When from base is decimal, the number must be a bigger than 0 and smaller than 256\n");
|
||||
return 0;
|
||||
}
|
||||
usage(argv);
|
||||
return 1;
|
||||
}
|
||||
char *choices[4] = { "bin", "oct", "dec", "hex" };
|
||||
validate_input(argv, choices);
|
||||
|
||||
char *from_base = argv[2];
|
||||
char *to_base = argv[4];
|
||||
char *number = argv[6];
|
||||
|
||||
if (!strcmp(from_base, to_base)) {
|
||||
printf("based: Cannot convert from same bases.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strncmp(from_base, "bin", 3) == 0) {
|
||||
if (strlen(number) != 8) {
|
||||
printf("based: Binary number must be 8 bits. If it is a 7 bits number, add a 0 first.\n");
|
||||
return 1;
|
||||
}
|
||||
if (strncmp(to_base, "oct", 3) == 0) {
|
||||
bin_to_oct(number);
|
||||
} else if (strncmp(to_base, "dec", 3) == 0) {
|
||||
bin_to_dec(number);
|
||||
} else if (strncmp(to_base, "hex", 3) == 0) {
|
||||
bin_to_hex(number);
|
||||
}
|
||||
} else if (strncmp(from_base, "oct", 3) == 0) {
|
||||
if (strlen(number) > 3) {
|
||||
printf("based: Octal number must be 3 or less than 3 digits");
|
||||
return 1;
|
||||
}
|
||||
if (strncmp(to_base, "bin", 3) == 0) {
|
||||
oct_to_bin(number);
|
||||
} else if (strncmp(to_base, "dec", 3) == 0) {
|
||||
oct_to_dec(number);
|
||||
} else if (strncmp(to_base, "hex", 3) == 0) {
|
||||
oct_to_hex(number);
|
||||
}
|
||||
} else if (strncmp(from_base, "dec", 3) == 0) {
|
||||
if (strlen(number) > 3 || atoi(number) > 255 || atoi(number) < 0) {
|
||||
printf("based: Decimal number must be 3 or less than 3 digits and must be between 0 and 255.\n");
|
||||
return 1;
|
||||
}
|
||||
if (strncmp(to_base, "bin", 3) == 0) {
|
||||
dec_to_bin(number);
|
||||
} else if (strncmp(to_base, "oct", 3) == 0) {
|
||||
dec_to_oct(number);
|
||||
} else if (strncmp(to_base, "hex", 3) == 0) {
|
||||
dec_to_hex(number);
|
||||
}
|
||||
} else if (strncmp(from_base, "hex", 3) == 0) {
|
||||
if (strlen(number) != 2) {
|
||||
printf("based: Hexadecimal number must be 2 digits.\n");
|
||||
return 1;
|
||||
}
|
||||
if (strncmp(to_base, "bin", 3) == 0) {
|
||||
hex_to_bin(number);
|
||||
} else if (strncmp(to_base, "oct", 3) == 0) {
|
||||
hex_to_oct(number);
|
||||
} else if (strncmp(to_base, "dec", 3) == 0) {
|
||||
hex_to_dec(number);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
15
config.h
Normal file
15
config.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
static const char *log_file_path = "sfb.log";
|
||||
/* For connection */
|
||||
static const int port = 5222; /* 8433 880 */
|
||||
/* Length of paste's random ID */
|
||||
static const int id_len = 4;
|
||||
/* Max size for paste */
|
||||
static const int max_file_size = 52428800; /* 50 MB */
|
||||
/* Dir to store paste */
|
||||
static const char *output_dir = "code";
|
||||
/* URL in output */
|
||||
static const char *url = "https://bin.night0721.xyz";
|
||||
/* Address to listen for connection */
|
||||
static const char *listen_addr = "0.0.0.0";
|
||||
/* Domain for client to connect */
|
||||
static const char *domain = "bin.night0721.xyz";
|
90
fbc.c
Normal file
90
fbc.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
FILE *file = fopen(argv[1], "rb");
|
||||
if (!file) {
|
||||
perror("fopen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* Determine file size */
|
||||
fseek(file, 0, SEEK_END);
|
||||
long file_size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char *buffer = malloc(file_size);
|
||||
if (!buffer) {
|
||||
perror("malloc");
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size_t bytes_read = fread(buffer, 1, file_size, file);
|
||||
if (bytes_read != file_size) {
|
||||
perror("fread");
|
||||
free(buffer);
|
||||
fclose(file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
char response[512];
|
||||
|
||||
/* Resolve domain to IP */
|
||||
struct hostent *server = gethostbyname(domain);
|
||||
if (server == NULL) {
|
||||
fprintf(stderr, "No such host %s", domain);
|
||||
}
|
||||
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0) {
|
||||
perror("socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
memcpy(&addr.sin_addr.s_addr, server->h_addr, server->h_length);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("connect");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (send(sockfd, buffer, file_size, 0) < 0) {
|
||||
perror("send");
|
||||
free(buffer);
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
memset(response, 0, sizeof(response));
|
||||
ssize_t bytes_received = recv(sockfd, response, sizeof(response) - 1, 0);
|
||||
if (bytes_received < 0) {
|
||||
perror("recv");
|
||||
close(sockfd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("%s", response);
|
||||
close(sockfd);
|
||||
return 0;
|
||||
}
|
87
index.html
Normal file
87
index.html
Normal file
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>sfb</title>
|
||||
<style>
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
color: #d7d4cf;
|
||||
background-color: rgb(30, 33, 34);
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
button {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.output {
|
||||
font-family: monospace;
|
||||
}
|
||||
code {
|
||||
display: block;
|
||||
background: #f4f4f4;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ddd;
|
||||
margin: 1rem 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
body > * {
|
||||
border-color: rgb(58, 62, 65);
|
||||
background-color: rgb(30, 33, 34);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>Suckless File Bin</pre>
|
||||
<pre>================</pre>
|
||||
<pre></pre>
|
||||
<pre>Temporary file hoster.</pre>
|
||||
<pre>You can either enter text below and click submit to create a link or use CURL/other http client to send POST request for creating links</pre>
|
||||
<pre>CURL example:</pre>
|
||||
<code>curl -F'file=@yourfile.png' https://bin.night0721.xyz</code>
|
||||
<pre>Server will responde with a URL to your file, e.g. https://bin.night0721.xyz/abcd</pre>
|
||||
<textarea id="pasteContent" placeholder="Type or paste your content here..."></textarea>
|
||||
<button onclick="submitPaste()">Submit</button>
|
||||
<pre id="output" class="output" style="display: none;"></pre>
|
||||
|
||||
<script>
|
||||
async function submitPaste() {
|
||||
const content = document.getElementById('pasteContent').value.trim();
|
||||
if (!content) {
|
||||
alert('Please enter some content.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('https://bin.night0721.xyz', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'text/plain' },
|
||||
body: content
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server responded with status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.text();
|
||||
const output = document.getElementById('output');
|
||||
output.style.display = 'block';
|
||||
output.innerHTML = `File URL: <a href="${result}" target="_blank">${result}</a>`;
|
||||
} catch (error) {
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</body></html>
|
32
nginx.conf
Normal file
32
nginx.conf
Normal file
|
@ -0,0 +1,32 @@
|
|||
# HTTP
|
||||
server {
|
||||
server_name bin.night0721.xyz;
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:9999;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
client_max_body_size 512M;
|
||||
}
|
||||
}
|
||||
|
||||
# SFP
|
||||
server {
|
||||
server_name bin.night0721.xyz;
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
root /home/night/code/;
|
||||
index index.txt index.html;
|
||||
}
|
||||
}
|
||||
|
266
sfb.c
Normal file
266
sfb.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
/* For slug generation */
|
||||
const char *symbols = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
/* Permission for directories */
|
||||
const int permission = S_IRWXU | S_IRGRP | S_IROTH | S_IXOTH | S_IXGRP;
|
||||
|
||||
typedef struct {
|
||||
int socket;
|
||||
struct sockaddr_in address;
|
||||
} connection;
|
||||
|
||||
void
|
||||
die(char *err)
|
||||
{
|
||||
fprintf(stderr, "%s\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printf("[ERROR] ");
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void
|
||||
status(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
printf("[LOG] ");
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create string with current date and time
|
||||
*/
|
||||
static void
|
||||
get_date(char *buf)
|
||||
{
|
||||
time_t cur_time = time(NULL);
|
||||
|
||||
/* Save data to provided buffer */
|
||||
if (ctime_r(&cur_time, buf) == NULL) {
|
||||
/* Couldn't get date, set first byte to 0 so it won't be displayed */
|
||||
buf[0] = 0;
|
||||
return;
|
||||
}
|
||||
/* Remove additional new line */
|
||||
buf[strlen(buf) - 1] = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
save_entry(const char *ip, const char *hostname, const char *id)
|
||||
{
|
||||
FILE *f = fopen(log_file_path, "a");
|
||||
if (!f) {
|
||||
error("Error opening log file");
|
||||
return;
|
||||
}
|
||||
|
||||
char date[26];
|
||||
get_date(date);
|
||||
|
||||
/* Write request to file */
|
||||
fprintf(f, "[%s] [%s] [%s] [%s]\n", date, ip, hostname, id);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void *
|
||||
handle_connection(void *args)
|
||||
{
|
||||
connection *c = (connection *) args;
|
||||
|
||||
/* Get client's IP */
|
||||
const char *ip = inet_ntoa(c->address.sin_addr);
|
||||
|
||||
/* Get client's hostname */
|
||||
char hostname[512];
|
||||
if (getnameinfo((struct sockaddr *)&c->address, sizeof(c->address),
|
||||
hostname, sizeof(hostname), NULL, 0, 0) != 0 ) {
|
||||
/* Couldn't resolve a hostname */
|
||||
strcpy(hostname, "N/A");
|
||||
}
|
||||
|
||||
char date[26];
|
||||
get_date(date);
|
||||
status("[%s] [%s] [%s]: New connection", date, ip, hostname);
|
||||
|
||||
uint8_t *buffer = malloc(max_file_size);
|
||||
if (!buffer) {
|
||||
error("Error allocating memory");
|
||||
goto quit;
|
||||
}
|
||||
memset(buffer, 0, max_file_size);
|
||||
|
||||
const int r = recv(c->socket, buffer, max_file_size, 0);
|
||||
if (r <= 0) {
|
||||
/* TODO: log unsuccessful and rejected connections */
|
||||
error("No data received from the client");
|
||||
goto quit;
|
||||
} else {
|
||||
buffer[r] = 0;
|
||||
/* TODO: Check if requested was performed with a known protocol */
|
||||
|
||||
/* Generate id */
|
||||
char id[id_len + 1];
|
||||
for (int i = 0; i < id_len; i++) {
|
||||
int n = rand() % strlen(symbols);
|
||||
id[i] = symbols[n];
|
||||
}
|
||||
id[id_len] = 0;
|
||||
|
||||
/* 1 for slash and 1 for null */
|
||||
size_t len = strlen(output_dir) + id_len + 2;
|
||||
|
||||
/* Create path */
|
||||
char path[len];
|
||||
snprintf(path, len, "%s/%s", output_dir, id);
|
||||
|
||||
/* Try create directory for paste */
|
||||
if (mkdir(path, permission) != 0) {
|
||||
error("Error creating directory for paste");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
/* Save to file */
|
||||
const char *file_name = "index.txt";
|
||||
|
||||
len += strlen(file_name) + 1;
|
||||
|
||||
/* Construct path */
|
||||
char paste_path[len];
|
||||
snprintf(paste_path, len, "%s/%s", path, file_name);
|
||||
|
||||
/* Save file */
|
||||
FILE *f = fopen(paste_path, "w");
|
||||
if (!f) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (fprintf(f, "%s", buffer) < 0) {
|
||||
fclose(f);
|
||||
goto quit;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
/* Write a response to the user */
|
||||
const size_t url_len = strlen(url) + id_len + 3;
|
||||
|
||||
char full_url[url_len];
|
||||
snprintf(full_url, url_len, "%s/%s\n", url, id);
|
||||
|
||||
/* Send the response */
|
||||
write(c->socket, full_url, url_len);
|
||||
status("[%s] [%s] [%s]: Received %d bytes, saved to %s", date, ip, hostname, r, id);
|
||||
save_entry(ip, hostname, id);
|
||||
goto quit;
|
||||
}
|
||||
quit:
|
||||
free(buffer);
|
||||
close(c->socket);
|
||||
free(c);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
srand(time(NULL));
|
||||
|
||||
mkdir(output_dir, permission);
|
||||
if (access(output_dir, W_OK) != 0) {
|
||||
error("Output directory is not writable");
|
||||
return -1;
|
||||
}
|
||||
FILE *f = fopen(log_file_path, "a+");
|
||||
if (!f) {
|
||||
die("Cannot open log file");
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reuse address */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1} , sizeof(int)) < 0) {
|
||||
perror("setsockopt");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = inet_addr(listen_addr);
|
||||
address.sin_port = htons(port);
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &address, sizeof(address)) < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(fd, 128) != 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status("spb listening on %s:%d", listen_addr, port);
|
||||
|
||||
while (1) {
|
||||
/* Create a thread for each connection */
|
||||
struct sockaddr_in address;
|
||||
socklen_t addlen = sizeof(address);
|
||||
|
||||
/* Get client fd */
|
||||
int s = accept(fd, (struct sockaddr *) &address, &addlen);
|
||||
if (s < 0) {
|
||||
error("Error on accepting connection!");
|
||||
continue;
|
||||
}
|
||||
|
||||
connection *c = malloc(sizeof(connection));
|
||||
if (!c) {
|
||||
die("Error allocating memory");
|
||||
}
|
||||
c->socket = s;
|
||||
c->address = address;
|
||||
|
||||
pthread_t id;
|
||||
|
||||
if (pthread_create(&id, NULL, &handle_connection, c) != 0) {
|
||||
error("Error spawning thread");
|
||||
continue;
|
||||
}
|
||||
pthread_detach(id);
|
||||
}
|
||||
return 0;
|
||||
}
|
121
sfb.py
Normal file
121
sfb.py
Normal file
|
@ -0,0 +1,121 @@
|
|||
from flask import Flask, request, jsonify, send_from_directory, send_file, render_template_string
|
||||
from flask_cors import CORS, cross_origin
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime
|
||||
from pygments import highlight
|
||||
from pygments.lexers import guess_lexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
||||
# Configuration
|
||||
OUTPUT_DIR = "code"
|
||||
LOG_FILE = "spb.log"
|
||||
SYMBOLS = string.ascii_lowercase + string.ascii_uppercase + string.digits
|
||||
ID_LEN = 4
|
||||
PORT = 9999
|
||||
URL = f"https://bin.night0721.xyz"
|
||||
|
||||
app = Flask(__name__)
|
||||
cors = CORS(app)
|
||||
app.config['CORS_HEADERS'] = 'Content-Type'
|
||||
|
||||
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
||||
|
||||
def generate_id():
|
||||
return ''.join(random.choices(SYMBOLS, k=ID_LEN))
|
||||
|
||||
def log_request(ip, hostname, unique_id):
|
||||
"""Log the request details."""
|
||||
timestamp = datetime.now().ctime()
|
||||
with open(LOG_FILE, 'a') as log_file:
|
||||
fmtstr = f"[{timestamp}] [{ip}] [{hostname}] [{unique_id}]"
|
||||
print(fmtstr)
|
||||
log_file.write(fmtstr + "\n")
|
||||
|
||||
@app.route('/', methods=['POST'])
|
||||
@cross_origin()
|
||||
def upload():
|
||||
try:
|
||||
id = generate_id()
|
||||
if 'file' in request.files:
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({"error": "No file selected"}), 400
|
||||
filename = id
|
||||
file.save(os.path.join(OUTPUT_DIR, filename))
|
||||
else:
|
||||
data = request.data.decode('utf-8')
|
||||
if not data:
|
||||
return jsonify({"error": "No data provided"}), 400
|
||||
filename = os.path.join(OUTPUT_DIR, id)
|
||||
with open(filename, 'w') as f:
|
||||
f.write(data)
|
||||
f.write("\n")
|
||||
f.close()
|
||||
# IP Hostname
|
||||
log_request(request.remote_addr, request.host, filename)
|
||||
|
||||
return f"{URL}/{id}\n"
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/', methods=['GET'])
|
||||
@cross_origin()
|
||||
def index():
|
||||
return send_from_directory('.', 'index.html')
|
||||
|
||||
@app.route("/<id>", methods=["GET"])
|
||||
def get_file(id):
|
||||
file_path = os.path.join(OUTPUT_DIR, id)
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
return jsonify({"error": f"File '{id}' not found"}), 404
|
||||
|
||||
try:
|
||||
# Send the file content
|
||||
return send_file(file_path, as_attachment=False)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
HTML_TEMPLATE = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
{{ style }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>{{ content|safe }}</pre>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
@app.route("/<id>/raw", methods=["GET"])
|
||||
def get_file_raw(id):
|
||||
file_path = os.path.join(OUTPUT_DIR, id)
|
||||
|
||||
if not os.path.isfile(file_path):
|
||||
return jsonify({"error": f"File '{id}' not found"}), 404
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as file:
|
||||
content = file.read()
|
||||
lexer = guess_lexer(content)
|
||||
formatter = HtmlFormatter()
|
||||
highlighted_content = highlight(content, lexer, formatter)
|
||||
style = formatter.get_style_defs()
|
||||
|
||||
return render_template_string(
|
||||
HTML_TEMPLATE,
|
||||
id=id,
|
||||
content=highlighted_content,
|
||||
style=style,
|
||||
)
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
app.run(host="0.0.0.0", port=PORT, debug=False)
|
Loading…
Reference in a new issue