embedded-framework/utils/WebServer/src/WebServer.cpp
2024-04-19 15:36:45 +08:00

230 lines
7.3 KiB
C++

/*
* Copyright (c) 2023 Fancy Code.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "WebServer.h"
#include "ILog.h"
#include "goahead.h"
#include "js.h"
#include <signal.h>
static int finished = 0;
static HttpHandleCallback gHttpHandle = NULL;
constexpr int UNKNOWN_LENGTH = -1;
static void sigHandler(int signo)
{
LogInfo("Stop goahead web server.\n");
finished = 1;
}
static void CheckUploadDir(void)
{
const char *directory = GOAHEAD_UPLOAD_TMP_PATH;
if (access(directory, F_OK) != 0) {
int result = mkdir(directory, 0777);
if (result == 0) {
LogInfo("mkdir upload tmp path successfuly.\n");
}
else {
LogError("mkdir upload tmp path failed.\n");
}
}
const char *directory2 = GOAHEAD_UPLOAD_PATH;
if (access(directory2, F_OK) != 0) {
int result = mkdir(directory2, 0777);
if (result == 0) {
LogInfo("mkdir upload path successfuly.\n");
}
else {
LogError("mkdir upload path failed.\n");
}
}
}
static void logHeader(void)
{
char home[ME_GOAHEAD_LIMIT_STRING];
char *result = getcwd(home, sizeof(home));
if (nullptr == result) {
LogWarning("Can't get path.\n");
}
logmsg(2, "Configuration for %s", ME_TITLE);
logmsg(2, "---------------------------------------------");
logmsg(2, "Version: %s", ME_VERSION);
logmsg(2, "BuildType: %s", ME_DEBUG ? "Debug" : "Release");
logmsg(2, "CPU: %s", ME_CPU);
logmsg(2, "OS: %s", ME_OS);
logmsg(2, "Host: %s", websGetServer());
logmsg(2, "Directory: %s", home);
logmsg(2, "Documents: %s", websGetDocuments());
logmsg(2, "Configure: %s", ME_CONFIG_CMD);
logmsg(2, "---------------------------------------------");
}
void initPlatform(void)
{
signal(SIGINT, sigHandler);
signal(SIGTERM, sigHandler);
signal(SIGKILL, sigHandler);
signal(SIGPIPE, SIG_IGN);
}
static void response_handle(const char *responseStr, void *context)
{
struct Webs *wp = (struct Webs *)context;
if (NULL != responseStr) {
websWrite(wp, "%s", responseStr);
}
}
static void get_thumbnail_handle(const char *thumbnailUrl, void *context)
{
struct Webs *wp = (struct Webs *)context;
if (nullptr == thumbnailUrl) {
LogError("thumbnailUrl is nullptr.\n");
return;
}
FILE *file = nullptr;
unsigned char *buffer = nullptr;
size_t bytesRead = 0;
long int fsize = 0;
file = fopen(thumbnailUrl, "rb");
if (file == nullptr) {
LogError("Open picture failed[%s].\n", thumbnailUrl);
goto END;
}
fseek(file, 0, SEEK_END);
fsize = ftell(file);
rewind(file);
buffer = (unsigned char *)malloc(fsize);
if (!buffer) {
LogError("malloc failed.\n");
goto END;
}
while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) {
websWriteBlock(wp, (cchar *)buffer, bytesRead);
}
END:
if (buffer) {
free(buffer);
}
if (file) {
fclose(file);
}
}
static bool AppRequestHandle(Webs *wp)
{
websSetStatus(wp, 200);
websWriteHeaders(wp, UNKNOWN_LENGTH, 0);
websWriteHeader(wp, "Content-Type", "text/plain");
websWriteEndHeaders(wp);
gHttpHandle(wp->url, 0, response_handle, wp);
websDone(wp);
return 1;
}
static bool AppUploadHandle(Webs *wp)
{
WebsKey *s;
WebsUpload *up;
char *upfile = nullptr;
websSetStatus(wp, 200);
websWriteHeaders(wp, UNKNOWN_LENGTH, 0);
websWriteHeader(wp, "Content-Type", "text/plain");
websWriteEndHeaders(wp);
if (scaselessmatch(wp->method, "POST")) {
for (s = hashFirst(wp->files); s; s = hashNext(wp->files, s)) {
up = (WebsUpload *)s->content.value.symbol;
// LogInfo("FILE: %s\r\n", s->name.value.string);
// LogInfo("FILENAME=%s\r\n", up->filename);
LogInfo("CLIENT=%s\r\n", up->clientFilename);
// LogInfo("TYPE=%s\r\n", up->contentType);
LogInfo("SIZE=%d\r\n", up->size);
upfile = sfmt(GOAHEAD_UPLOAD_PATH "/%s", up->clientFilename);
if (rename(up->filename, upfile) < 0) {
error("Cannot rename uploaded file: %s to %s, errno %d", up->filename, upfile, errno);
}
LogInfo("Upload file:%s\n", upfile);
wfree(upfile);
upfile = nullptr;
}
gHttpHandle(wp->url, 0, response_handle, wp);
}
websDone(wp);
return 1;
}
static bool AppGetThumbnail(Webs *wp)
{
LogInfo("AppGetThumbnail url = %s\n", wp->url);
websSetStatus(wp, 200);
websWriteHeaders(wp, UNKNOWN_LENGTH, 0);
websWriteHeader(wp, "Content-Type", "image/jpeg");
websWriteEndHeaders(wp);
gHttpHandle(wp->url, 0, get_thumbnail_handle, wp);
websDone(wp);
return 1;
}
StatusCode WebServerInit(const WebServerParam webParam)
{
CheckUploadDir();
websSetDebug(1);
logSetPath("stdout:2");
const char *documents = GOAHEAD_DOCUMENTS_PATH;
constexpr int BUF_LENGTH = 128;
char routePath[BUF_LENGTH] = {0};
char authPath[BUF_LENGTH] = {0};
char listen[BUF_LENGTH] = {0};
snprintf(routePath, BUF_LENGTH, "%s/route.txt", GOAHEAD_CONFIG_FILE_PATH);
snprintf(authPath, BUF_LENGTH, "%s/auth.txt", GOAHEAD_CONFIG_FILE_PATH);
snprintf(listen, BUF_LENGTH, "%s:%d", webParam.mIp, webParam.mPort);
LogInfo("GOAHEAD_CONFIG_FILE_PATH = %s\n", GOAHEAD_CONFIG_FILE_PATH);
LogInfo("listen = %s\n", listen);
initPlatform();
if (websOpen(documents, routePath) < 0) {
LogError("Cannot initialize server. Exiting.\n");
return CreateStatusCode(STATUS_CODE_NOT_OK);
}
logHeader();
if (websLoad(authPath) < 0) {
LogError("Cannot load %s", authPath);
return CreateStatusCode(STATUS_CODE_NOT_OK);
}
if (websListen(listen) < 0) {
return CreateStatusCode(STATUS_CODE_NOT_OK);
}
if (nullptr != webParam.mHttpRequestHandle) {
gHttpHandle = webParam.mHttpRequestHandle;
websDefineHandler("appRequestHandle", 0, AppRequestHandle, 0, 0);
websAddRoute("/app", "appRequestHandle", 0);
websDefineHandler("AppUploadHandle", 0, AppUploadHandle, 0, 0);
websAddRoute("/upload", "AppUploadHandle", 0);
websDefineHandler("AppGetThumbnail", 0, AppGetThumbnail, 0, 0);
websAddRoute("/app/getthumbnail", "AppGetThumbnail", 0);
}
websServiceEvents(&finished);
logmsg(1, "Instructed to exit\n");
websClose();
return CreateStatusCode(STATUS_CODE_OK);
}
StatusCode WebServerExit(void)
{
LogInfo("Stop goahead web server.\n");
finished = 1;
return CreateStatusCode(STATUS_CODE_OK);
}
StatusCode WebServerUnInit(void)
{
LogInfo("WebServerUnInit.\n");
return CreateStatusCode(STATUS_CODE_OK);
}