Compare commits

...

6 Commits

41 changed files with 415 additions and 278 deletions

View File

@ -97,9 +97,12 @@ else ()
target_compile_options( target_compile_options(
sist2 sist2
PRIVATE PRIVATE
-Ofast -Ofast
#-march=native
-fno-stack-protector -fno-stack-protector
-fomit-frame-pointer -fomit-frame-pointer
#-freciprocal-math
) )
endif () endif ()
@ -121,11 +124,13 @@ target_link_libraries(
CURL::libcurl CURL::libcurl
pthread pthread
magic #magic
c c
scan scan
/usr/lib/x86_64-linux-gnu/libmagic.so.1
) )
add_custom_target( add_custom_target(

View File

@ -9,7 +9,7 @@ RUN strip sist2 || mv sist2_debug sist2
FROM --platform="linux/amd64" ubuntu:21.10 FROM --platform="linux/amd64" ubuntu:21.10
RUN apt update && apt install -y curl libasan5 && rm -rf /var/lib/apt/lists/* RUN apt update && apt install -y curl libasan5 libmagic1 && rm -rf /var/lib/apt/lists/*
RUN mkdir -p /usr/share/tessdata && \ RUN mkdir -p /usr/share/tessdata && \
cd /usr/share/tessdata/ && \ cd /usr/share/tessdata/ && \

View File

@ -103,7 +103,7 @@ Made by simon987 <me@simon987.net>. Released under GPL-3.0
* `--thumbnail-count` * `--thumbnail-count`
Maximum number of thumbnails to generate. When set to a value >= 2, thumbnails for video previews Maximum number of thumbnails to generate. When set to a value >= 2, thumbnails for video previews
will be generated. The actual number of thumbnails generated depends on the length of the video (maximum 1 image will be generated. The actual number of thumbnails generated depends on the length of the video (maximum 1 image
every ~5s). Set to 0 to completely disable thumbnails. every ~7s). Set to 0 to completely disable thumbnails.
* `--content-size` * `--content-size`
Number of bytes of text to be extracted from the content of files (plain text, PDFs etc.). Number of bytes of text to be extracted from the content of files (plain text, PDFs etc.).
Repeated whitespace and special characters do not count toward this limit. Repeated whitespace and special characters do not count toward this limit.

View File

@ -55,5 +55,37 @@
] ]
} }
} }
},
"mappings": {
"dynamic_templates": [
{
"keyword_fields": {
"match_mapping_type": "string",
"match": "kw_*",
"mapping": {
"type": "keyword"
}
}
},
{
"integer_fields": {
"match_mapping_type": "*",
"match": "int_*",
"mapping": {
"type": "integer"
}
}
},
{
"meta_fields": {
"match_mapping_type": "*",
"match": "mt_*",
"mapping": {
"type": "keyword",
"index": false
}
}
}
]
} }
} }

View File

@ -1,2 +1,3 @@
docker run --rm -it -p 9200:9200 -e "discovery.type=single-node" \ docker run --rm -it --name "sist2-dev-es"\
-p 9200:9200 -e "discovery.type=single-node" \
-e "ES_JAVA_OPTS=-Xms8g -Xmx8g" elasticsearch:7.14.0 -e "ES_JAVA_OPTS=-Xms8g -Xmx8g" elasticsearch:7.14.0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,6 @@
"axios": "^0.25.0", "axios": "^0.25.0",
"bootstrap-vue": "^2.21.2", "bootstrap-vue": "^2.21.2",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"crypto-es": "^1.2.7",
"d3": "^5.16.0", "d3": "^5.16.0",
"date-fns": "^2.21.3", "date-fns": "^2.21.3",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",
@ -5261,11 +5260,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/crypto-es": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/crypto-es/-/crypto-es-1.2.7.tgz",
"integrity": "sha512-UUqiVJ2gUuZFmbFsKmud3uuLcNP2+Opt+5ysmljycFCyhA0+T16XJmo1ev/t5kMChMqWh7IEvURNCqsg+SjZGQ=="
},
"node_modules/css-color-names": { "node_modules/css-color-names": {
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@ -19621,11 +19615,6 @@
"randomfill": "^1.0.3" "randomfill": "^1.0.3"
} }
}, },
"crypto-es": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/crypto-es/-/crypto-es-1.2.7.tgz",
"integrity": "sha512-UUqiVJ2gUuZFmbFsKmud3uuLcNP2+Opt+5ysmljycFCyhA0+T16XJmo1ev/t5kMChMqWh7IEvURNCqsg+SjZGQ=="
},
"css-color-names": { "css-color-names": {
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",

View File

@ -11,7 +11,6 @@
"axios": "^0.25.0", "axios": "^0.25.0",
"bootstrap-vue": "^2.21.2", "bootstrap-vue": "^2.21.2",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"crypto-es": "^1.2.7",
"d3": "^5.16.0", "d3": "^5.16.0",
"date-fns": "^2.21.3", "date-fns": "^2.21.3",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",

View File

@ -1,6 +1,5 @@
import axios from "axios"; import axios from "axios";
import {ext, strUnescape, lum} from "./util"; import {ext, strUnescape, lum} from "./util";
import CryptoES from 'crypto-es';
export interface EsTag { export interface EsTag {
id: string id: string
@ -30,7 +29,6 @@ export interface EsHit {
_index: string _index: string
_id: string _id: string
_score: number _score: number
_path_md5: string
_type: string _type: string
_tags: Tag[] _tags: Tag[]
_seq: number _seq: number
@ -249,11 +247,6 @@ class Sist2Api {
res.hits.hits.forEach((hit: EsHit) => { res.hits.hits.forEach((hit: EsHit) => {
hit["_source"]["name"] = strUnescape(hit["_source"]["name"]); hit["_source"]["name"] = strUnescape(hit["_source"]["name"]);
hit["_source"]["path"] = strUnescape(hit["_source"]["path"]); hit["_source"]["path"] = strUnescape(hit["_source"]["path"]);
hit["_path_md5"] = CryptoES.MD5(
hit["_source"]["path"] +
(hit["_source"]["path"] ? "/" : "") +
hit["_source"]["name"] + ext(hit)
).toString();
this.setHitProps(hit); this.setHitProps(hit);
this.setHitTags(hit); this.setHitTags(hit);
@ -380,8 +373,7 @@ class Sist2Api {
return axios.post(`${this.baseUrl}tag/` + hit["_source"]["index"], { return axios.post(`${this.baseUrl}tag/` + hit["_source"]["index"], {
delete: false, delete: false,
name: tag, name: tag,
doc_id: hit["_id"], doc_id: hit["_id"]
path_md5: hit._path_md5
}); });
} }
@ -389,8 +381,7 @@ class Sist2Api {
return axios.post(`${this.baseUrl}tag/` + hit["_source"]["index"], { return axios.post(`${this.baseUrl}tag/` + hit["_source"]["index"], {
delete: true, delete: true,
name: tag, name: tag,
doc_id: hit["_id"], doc_id: hit["_id"]
path_md5: hit._path_md5
}); });
} }

View File

@ -1,6 +1,7 @@
<template> <template>
<div> <div :class="{'disable-animations': $store.state.optSimpleLightbox}">
<FsLightbox <FsLightbox
ref="lightbox"
:key="lightboxKey" :key="lightboxKey"
:toggler="showLightbox" :toggler="showLightbox"
:sources="lightboxSources" :sources="lightboxSources"
@ -10,7 +11,7 @@
:source-index="lightboxSlide" :source-index="lightboxSlide"
:custom-toolbar-buttons="customButtons" :custom-toolbar-buttons="customButtons"
:slideshow-time="$store.getters.optLightboxSlideDuration * 1000" :slideshow-time="$store.getters.optLightboxSlideDuration * 1000"
:zoom-increment="0.5" :zoom-increment="0.25"
:load-only-current-source="$store.getters.optLightboxLoadOnlyCurrent" :load-only-current-source="$store.getters.optLightboxLoadOnlyCurrent"
:on-close="onClose" :on-close="onClose"
:on-open="onShow" :on-open="onShow"
@ -29,6 +30,7 @@ export default {
components: {FsLightbox}, components: {FsLightbox},
data() { data() {
return { return {
disableAnimations: true,
customButtons: [ customButtons: [
{ {
viewBox: "0 0 384.928 384.928", viewBox: "0 0 384.928 384.928",
@ -64,7 +66,83 @@ export default {
return this.$store.getters["uiLightboxTypes"]; return this.$store.getters["uiLightboxTypes"];
} }
}, },
mounted() {
const listener = document.onkeydown;
document.onkeydown = (e) => {
const ret = this.keyDownListener(e)
if (listener && ret) {
return listener(e);
}
};
},
methods: { methods: {
keyDownListener(e) {
if (this.$refs.lightbox === undefined) {
return true;
}
const lightboxStore = this.$refs.lightbox.fsLightboxStore.slice(-1)[0];
switch (e.key) {
case " ": {
console.log("SPACE")
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
// Find video at current slide, toggle play/pause
[...document.getElementsByClassName("fslightbox-absoluted")].forEach(elem => {
if (elem.style.transform === "translate(0px)" || elem.style.transform === "translate(0px, 0px)") {
const vid = elem.getElementsByTagName("video")[0];
console.log(elem)
console.log(vid)
if (vid) {
if (vid.paused) {
vid.play();
console.log("PLAY")
} else {
vid.pause()
console.log("PAUSE")
}
}
}
return false;
});
return false;
}
case "ArrowUp":
case "k": {
if (!lightboxStore.data.isThumbing) {
lightboxStore.core.thumbsToggler.toggleThumbs();
}
return false;
}
case "ArrowDown":
case "j": {
if (lightboxStore.data.isThumbing) {
lightboxStore.core.thumbsToggler.toggleThumbs();
}
return false;
}
case "h": {
lightboxStore.core.slideIndexChanger.jumpTo(lightboxStore.core.stageManager.getPreviousSlideIndex());
break;
}
case "l": {
lightboxStore.core.slideIndexChanger.jumpTo(lightboxStore.core.stageManager.getNextSlideIndex());
return false;
}
}
return true;
},
onDownloadClick() { onDownloadClick() {
const url = this.lightboxSources[this.lightboxSlide]; const url = this.lightboxSources[this.lightboxSlide];
@ -125,4 +203,20 @@ export default {
.fslightbox-toolbar-button:nth-child(7) { .fslightbox-toolbar-button:nth-child(7) {
order: 7; order: 7;
} }
.disable-animations .fslightbox-container {
background: rgba(30,30,30,.9);
}
.disable-animations .fslightbox-transform-transition {
transition: none;
}
.disable-animations .fslightbox-fade-in-strong {
animation: none;
}
.fslightbox-container video, .fslightbox-container img {
cursor: unset !important;
}
</style> </style>

View File

@ -72,7 +72,8 @@ export default {
hideLegacy: "Hide the 'legacyES' Elasticsearch notice", hideLegacy: "Hide the 'legacyES' Elasticsearch notice",
updateMimeMap: "Update the Media Types tree in real time", updateMimeMap: "Update the Media Types tree in real time",
useDatePicker: "Use a Date Picker component rather than a slider", useDatePicker: "Use a Date Picker component rather than a slider",
vidPreviewInterval: "Video preview frame duration in ms" vidPreviewInterval: "Video preview frame duration in ms",
simpleLightbox: "Disable animations in image viewer",
}, },
queryMode: { queryMode: {
simple: "Simple", simple: "Simple",
@ -239,7 +240,8 @@ export default {
hideLegacy: "Masquer la notice 'legacyES' Elasticsearch", hideLegacy: "Masquer la notice 'legacyES' Elasticsearch",
updateMimeMap: "Mettre à jour l'arbre de Types de médias en temps réel", updateMimeMap: "Mettre à jour l'arbre de Types de médias en temps réel",
useDatePicker: "Afficher un composant « Date Picker » plutôt qu'un slider", useDatePicker: "Afficher un composant « Date Picker » plutôt qu'un slider",
vidPreviewInterval: "Durée des images d'aperçu video en millisecondes" vidPreviewInterval: "Durée des images d'aperçu video en millisecondes",
simpleLightbox: "Désactiver les animations du visualiseur d'images",
}, },
queryMode: { queryMode: {
simple: "Simple", simple: "Simple",
@ -406,7 +408,8 @@ export default {
hideLegacy: "隐藏'legacyES' Elasticsearch 通知", hideLegacy: "隐藏'legacyES' Elasticsearch 通知",
updateMimeMap: "媒体类型树的实时更新", updateMimeMap: "媒体类型树的实时更新",
useDatePicker: "使用日期选择器组件而不是滑块", useDatePicker: "使用日期选择器组件而不是滑块",
vidPreviewInterval: "视频预览帧的持续时间,以毫秒为单位" vidPreviewInterval: "视频预览帧的持续时间,以毫秒为单位",
simpleLightbox: "在图片查看器中,禁用动画",
}, },
queryMode: { queryMode: {
simple: "简单", simple: "简单",

View File

@ -51,6 +51,7 @@ export default new Vuex.Store({
optUpdateMimeMap: false, optUpdateMimeMap: false,
optUseDatePicker: false, optUseDatePicker: false,
optVidPreviewInterval: 700, optVidPreviewInterval: 700,
optSimpleLightbox: true,
_onLoadSelectedIndices: [] as string[], _onLoadSelectedIndices: [] as string[],
_onLoadSelectedMimeTypes: [] as string[], _onLoadSelectedMimeTypes: [] as string[],
@ -161,6 +162,7 @@ export default new Vuex.Store({
setOptUpdateMimeMap: (state, val) => state.optUpdateMimeMap = val, setOptUpdateMimeMap: (state, val) => state.optUpdateMimeMap = val,
setOptUseDatePicker: (state, val) => state.optUseDatePicker = val, setOptUseDatePicker: (state, val) => state.optUseDatePicker = val,
setOptVidPreviewInterval: (state, val) => state.optVidPreviewInterval = val, setOptVidPreviewInterval: (state, val) => state.optVidPreviewInterval = val,
setOptSimpleLightbox: (state, val) => state.optSimpleLightbox = val,
setOptLightboxLoadOnlyCurrent: (state, val) => state.optLightboxLoadOnlyCurrent = val, setOptLightboxLoadOnlyCurrent: (state, val) => state.optLightboxLoadOnlyCurrent = val,
setOptLightboxSlideDuration: (state, val) => state.optLightboxSlideDuration = val, setOptLightboxSlideDuration: (state, val) => state.optLightboxSlideDuration = val,
@ -378,5 +380,6 @@ export default new Vuex.Store({
optUpdateMimeMap: state => state.optUpdateMimeMap, optUpdateMimeMap: state => state.optUpdateMimeMap,
optUseDatePicker: state => state.optUseDatePicker, optUseDatePicker: state => state.optUseDatePicker,
optVidPreviewInterval: state => state.optVidPreviewInterval, optVidPreviewInterval: state => state.optVidPreviewInterval,
optSimpleLightbox: state => state.optSimpleLightbox,
} }
}) })

View File

@ -45,6 +45,11 @@
<b-form-checkbox :checked="optUseDatePicker" @input="setOptUseDatePicker"> <b-form-checkbox :checked="optUseDatePicker" @input="setOptUseDatePicker">
{{ $t("opt.useDatePicker") }} {{ $t("opt.useDatePicker") }}
</b-form-checkbox> </b-form-checkbox>
<b-form-checkbox :checked="optSimpleLightbox" @input="setOptSimpleLightbox">{{
$t("opt.simpleLightbox")
}}
</b-form-checkbox>
</b-card> </b-card>
<br/> <br/>
@ -239,6 +244,7 @@ export default {
"optUpdateMimeMap", "optUpdateMimeMap",
"optUseDatePicker", "optUseDatePicker",
"optVidPreviewInterval", "optVidPreviewInterval",
"optSimpleLightbox",
]), ]),
clientWidth() { clientWidth() {
return window.innerWidth; return window.innerWidth;
@ -285,6 +291,7 @@ export default {
"setOptUpdateMimeMap", "setOptUpdateMimeMap",
"setOptUseDatePicker", "setOptUseDatePicker",
"setOptVidPreviewInterval", "setOptVidPreviewInterval",
"setOptSimpleLightbox",
]), ]),
onResetClick() { onResetClick() {
localStorage.removeItem("sist2_configuration"); localStorage.removeItem("sist2_configuration");

View File

@ -56,6 +56,22 @@ export default Vue.extend({
onThumbnailClick() { onThumbnailClick() {
window.open(`/f/${this.doc._id}`, "_blank"); window.open(`/f/${this.doc._id}`, "_blank");
}, },
findByCustomField(field, id) {
return {
query: {
bool: {
must: [
{
match: {
[field]: id
}
}
]
}
},
size: 1
}
},
findById(id) { findById(id) {
return { return {
query: { query: {
@ -103,6 +119,8 @@ export default Vue.extend({
query = this.findById(this.$route.query.byId); query = this.findById(this.$route.query.byId);
} else if (this.$route.query.byName) { } else if (this.$route.query.byName) {
query = this.findByName(this.$route.query.byName); query = this.findByName(this.$route.query.byName);
} else if (this.$route.query.by && this.$route.query.q) {
query = this.findByCustomField(this.$route.query.by, this.$route.query.q)
} }
if (query) { if (query) {

View File

@ -124,6 +124,9 @@ int scan_args_validate(scan_args_t *args, int argc, const char **argv) {
args->tn_count = DEFAULT_THUMBNAIL_COUNT; args->tn_count = DEFAULT_THUMBNAIL_COUNT;
} else if (args->tn_count == OPTION_VALUE_DISABLE) { } else if (args->tn_count == OPTION_VALUE_DISABLE) {
args->tn_count = 0; args->tn_count = 0;
} else if (args->tn_count > 1000) {
printf("Invalid value --thumbnail-count argument: %d. Must be <= 1000.\n", args->tn_size);
return 1;
} }
if (args->content_size == OPTION_VALUE_UNSPECIFIED) { if (args->content_size == OPTION_VALUE_UNSPECIFIED) {

View File

@ -45,7 +45,7 @@ void elastic_cleanup() {
destroy_indexer(Indexer); destroy_indexer(Indexer);
} }
void print_json(cJSON *document, const char id_str[MD5_STR_LENGTH]) { void print_json(cJSON *document, const char id_str[SIST_DOC_ID_LEN]) {
cJSON *line = cJSON_CreateObject(); cJSON *line = cJSON_CreateObject();
@ -72,19 +72,19 @@ void delete_document(const char* document_id_str, void* UNUSED(_data)) {
bulk_line->type = ES_BULK_LINE_DELETE; bulk_line->type = ES_BULK_LINE_DELETE;
bulk_line->next = NULL; bulk_line->next = NULL;
memcpy(bulk_line->path_md5_str, document_id_str, MD5_STR_LENGTH); strcpy(bulk_line->doc_id, document_id_str);
tpool_add_work(IndexCtx.pool, index_json_func, bulk_line); tpool_add_work(IndexCtx.pool, index_json_func, bulk_line);
} }
void index_json(cJSON *document, const char index_id_str[MD5_STR_LENGTH]) { void index_json(cJSON *document, const char doc_id[SIST_DOC_ID_LEN]) {
char *json = cJSON_PrintUnformatted(document); char *json = cJSON_PrintUnformatted(document);
size_t json_len = strlen(json); size_t json_len = strlen(json);
es_bulk_line_t *bulk_line = malloc(sizeof(es_bulk_line_t) + json_len + 2); es_bulk_line_t *bulk_line = malloc(sizeof(es_bulk_line_t) + json_len + 2);
bulk_line->type = ES_BULK_LINE_INDEX; bulk_line->type = ES_BULK_LINE_INDEX;
memcpy(bulk_line->line, json, json_len); memcpy(bulk_line->line, json, json_len);
memcpy(bulk_line->path_md5_str, index_id_str, MD5_STR_LENGTH); strcpy(bulk_line->doc_id, doc_id);
*(bulk_line->line + json_len) = '\n'; *(bulk_line->line + json_len) = '\n';
*(bulk_line->line + json_len + 1) = '\0'; *(bulk_line->line + json_len + 1) = '\0';
bulk_line->next = NULL; bulk_line->next = NULL;
@ -93,7 +93,7 @@ void index_json(cJSON *document, const char index_id_str[MD5_STR_LENGTH]) {
tpool_add_work(IndexCtx.pool, index_json_func, bulk_line); tpool_add_work(IndexCtx.pool, index_json_func, bulk_line);
} }
void execute_update_script(const char *script, int async, const char index_id[MD5_STR_LENGTH]) { void execute_update_script(const char *script, int async, const char index_id[SIST_INDEX_ID_LEN]) {
if (Indexer == NULL) { if (Indexer == NULL) {
Indexer = create_indexer(IndexCtx.es_url, IndexCtx.es_index); Indexer = create_indexer(IndexCtx.es_url, IndexCtx.es_index);
@ -167,7 +167,7 @@ void *create_bulk_buffer(int max, int *count, size_t *buf_len) {
snprintf( snprintf(
action_str, sizeof(action_str), action_str, sizeof(action_str),
"{\"index\":{\"_id\":\"%s\",\"_type\":\"_doc\",\"_index\":\"%s\"}}\n", "{\"index\":{\"_id\":\"%s\",\"_type\":\"_doc\",\"_index\":\"%s\"}}\n",
line->path_md5_str, Indexer->es_index line->doc_id, Indexer->es_index
); );
size_t action_str_len = strlen(action_str); size_t action_str_len = strlen(action_str);
@ -184,7 +184,7 @@ void *create_bulk_buffer(int max, int *count, size_t *buf_len) {
snprintf( snprintf(
action_str, sizeof(action_str), action_str, sizeof(action_str),
"{\"delete\":{\"_id\":\"%s\",\"_index\":\"%s\"}}\n", "{\"delete\":{\"_id\":\"%s\",\"_index\":\"%s\"}}\n",
line->path_md5_str, Indexer->es_index line->doc_id, Indexer->es_index
); );
size_t action_str_len = strlen(action_str); size_t action_str_len = strlen(action_str);
@ -263,7 +263,7 @@ void _elastic_flush(int max) {
if (r->status_code == 413) { if (r->status_code == 413) {
if (max <= 1) { if (max <= 1) {
LOG_ERRORF("elastic.c", "Single document too large, giving up: {%s}", Indexer->line_head->path_md5_str) LOG_ERRORF("elastic.c", "Single document too large, giving up: {%s}", Indexer->line_head->doc_id)
free_response(r); free_response(r);
free(buf); free(buf);
free_queue(1); free_queue(1);

View File

@ -8,7 +8,7 @@
typedef struct es_bulk_line { typedef struct es_bulk_line {
struct es_bulk_line *next; struct es_bulk_line *next;
char path_md5_str[MD5_STR_LENGTH]; char doc_id[SIST_DOC_ID_LEN];
int type; int type;
char line[0]; char line[0];
} es_bulk_line_t; } es_bulk_line_t;
@ -40,9 +40,9 @@ typedef struct es_indexer es_indexer_t;
void elastic_index_line(es_bulk_line_t *line); void elastic_index_line(es_bulk_line_t *line);
void print_json(cJSON *document, const char index_id_str[MD5_STR_LENGTH]); void print_json(cJSON *document, const char index_id_str[SIST_INDEX_ID_LEN]);
void index_json(cJSON *document, const char index_id_str[MD5_STR_LENGTH]); void index_json(cJSON *document, const char doc_id[SIST_INDEX_ID_LEN]);
void delete_document(const char *document_id_str, void* data); void delete_document(const char *document_id_str, void* data);
@ -59,6 +59,6 @@ char *elastic_get_status();
es_version_t *elastic_get_version(const char *es_url); es_version_t *elastic_get_version(const char *es_url);
void execute_update_script(const char *script, int async, const char index_id[MD5_STR_LENGTH]); void execute_update_script(const char *script, int async, const char index_id[SIST_INDEX_ID_LEN]);
#endif #endif

File diff suppressed because one or more lines are too long

View File

@ -124,9 +124,7 @@ char *build_json_string(document_t *doc) {
cJSON_AddStringToObject(json, "path", ""); cJSON_AddStringToObject(json, "path", "");
} }
char md5_str[MD5_STR_LENGTH]; cJSON_AddStringToObject(json, "_id", doc->doc_id);
buf2hex(doc->path_md5, MD5_DIGEST_LENGTH, md5_str);
cJSON_AddStringToObject(json, "_id", md5_str);
// Metadata // Metadata
meta_line_t *meta = doc->meta_head; meta_line_t *meta = doc->meta_head;
@ -452,7 +450,6 @@ void read_lines(const char *path, const line_processor_t processor) {
dyn_buffer_destroy(&buf); dyn_buffer_destroy(&buf);
fclose(file); fclose(file);
} }
void read_index_ndjson(const char *line, void *_data) { void read_index_ndjson(const char *line, void *_data) {
@ -462,7 +459,7 @@ void read_index_ndjson(const char *line, void* _data) {
read_index_bin_handle_line(line, index_id, func); read_index_bin_handle_line(line, index_id, func);
} }
void read_index(const char *path, const char index_id[MD5_STR_LENGTH], const char *type, index_func func) { void read_index(const char *path, const char index_id[SIST_INDEX_ID_LEN], const char *type, index_func func) {
if (strcmp(type, INDEX_TYPE_NDJSON) == 0) { if (strcmp(type, INDEX_TYPE_NDJSON) == 0) {
read_lines(path, (line_processor_t) { read_lines(path, (line_processor_t) {
.data = (void *[2]) {(void *) index_id, func}, .data = (void *[2]) {(void *) index_id, func},
@ -473,11 +470,11 @@ void read_index(const char *path, const char index_id[MD5_STR_LENGTH], const cha
static __thread GHashTable *IncrementalReadTable = NULL; static __thread GHashTable *IncrementalReadTable = NULL;
void json_put_incremental(cJSON *document, UNUSED(const char id_str[MD5_STR_LENGTH])) { void json_put_incremental(cJSON *document, UNUSED(const char doc_id[SIST_DOC_ID_LEN])) {
const char *path_md5_str = cJSON_GetObjectItem(document, "_id")->valuestring; const char *path_md5_str = cJSON_GetObjectItem(document, "_id")->valuestring;
const int mtime = cJSON_GetObjectItem(document, "mtime")->valueint; const int mtime = cJSON_GetObjectItem(document, "mtime")->valueint;
incremental_put_str(IncrementalReadTable, path_md5_str, mtime); incremental_put(IncrementalReadTable, path_md5_str, mtime);
} }
void incremental_read(GHashTable *table, const char *filepath, index_descriptor_t *desc) { void incremental_read(GHashTable *table, const char *filepath, index_descriptor_t *desc) {
@ -490,13 +487,11 @@ static __thread GHashTable *IncrementalNewTable = NULL;
static __thread store_t *IncrementalCopySourceStore = NULL; static __thread store_t *IncrementalCopySourceStore = NULL;
static __thread store_t *IncrementalCopyDestinationStore = NULL; static __thread store_t *IncrementalCopyDestinationStore = NULL;
void incremental_copy_handle_doc(cJSON *document, UNUSED(const char id_str[MD5_STR_LENGTH])) { void incremental_copy_handle_doc(cJSON *document, UNUSED(const char id_str[SIST_DOC_ID_LEN])) {
const char *path_md5_str = cJSON_GetObjectItem(document, "_id")->valuestring; const char *doc_id = cJSON_GetObjectItem(document, "_id")->valuestring;
unsigned char path_md5[MD5_DIGEST_LENGTH];
hex2buf(path_md5_str, MD5_STR_LENGTH - 1, path_md5);
if (cJSON_GetObjectItem(document, "parent") != NULL || incremental_get_str(IncrementalCopyTable, path_md5_str)) { if (cJSON_GetObjectItem(document, "parent") != NULL || incremental_get(IncrementalCopyTable, doc_id)) {
// Copy index line // Copy index line
cJSON_DeleteItemFromObject(document, "index"); cJSON_DeleteItemFromObject(document, "index");
char *json_str = cJSON_PrintUnformatted(document); char *json_str = cJSON_PrintUnformatted(document);
@ -510,9 +505,9 @@ void incremental_copy_handle_doc(cJSON *document, UNUSED(const char id_str[MD5_S
// Copy tn store contents // Copy tn store contents
size_t buf_len; size_t buf_len;
char *buf = store_read(IncrementalCopySourceStore, (char *) path_md5, sizeof(path_md5), &buf_len); char *buf = store_read(IncrementalCopySourceStore, (char *) doc_id, sizeof(doc_id), &buf_len);
if (buf_len != 0) { if (buf_len != 0) {
store_write(IncrementalCopyDestinationStore, (char *) path_md5, sizeof(path_md5), buf, buf_len); store_write(IncrementalCopyDestinationStore, (char *) doc_id, sizeof(doc_id), buf, buf_len);
free(buf); free(buf);
} }
} }
@ -536,20 +531,20 @@ void incremental_copy(store_t *store, store_t *dst_store, const char *filepath,
read_index(filepath, "", INDEX_TYPE_NDJSON, incremental_copy_handle_doc); read_index(filepath, "", INDEX_TYPE_NDJSON, incremental_copy_handle_doc);
} }
void incremental_delete_handle_doc(cJSON *document, UNUSED(const char id_str[MD5_STR_LENGTH])) { void incremental_delete_handle_doc(cJSON *document, UNUSED(const char id_str[SIST_DOC_ID_LEN])) {
char path_md5_n[MD5_STR_LENGTH + 1]; char doc_id_n[SIST_DOC_ID_LEN + 1];
path_md5_n[MD5_STR_LENGTH] = '\0'; doc_id_n[SIST_DOC_ID_LEN] = '\0';
path_md5_n[MD5_STR_LENGTH - 1] = '\n'; doc_id_n[SIST_DOC_ID_LEN - 1] = '\n';
const char *path_md5_str = cJSON_GetObjectItem(document, "_id")->valuestring; const char *doc_id = cJSON_GetObjectItem(document, "_id")->valuestring;
// do not delete archive virtual entries // do not delete archive virtual entries
if (cJSON_GetObjectItem(document, "parent") == NULL if (cJSON_GetObjectItem(document, "parent") == NULL
&& !incremental_get_str(IncrementalCopyTable, path_md5_str) && !incremental_get(IncrementalCopyTable, doc_id)
&& !incremental_get_str(IncrementalNewTable, path_md5_str) && !incremental_get(IncrementalNewTable, doc_id)
) { ) {
memcpy(path_md5_n, path_md5_str, MD5_STR_LENGTH - 1); memcpy(doc_id_n, doc_id, SIST_DOC_ID_LEN - 1);
zstd_write_string(path_md5_n, MD5_STR_LENGTH); zstd_write_string(doc_id, sizeof(doc_id_n));
} }
} }

View File

@ -12,7 +12,7 @@ typedef struct line_processor {
void (*func)(const char*, void*); void (*func)(const char*, void*);
} line_processor_t; } line_processor_t;
typedef void(*index_func)(cJSON *, const char[MD5_STR_LENGTH]); typedef void(*index_func)(cJSON *, const char[SIST_DOC_ID_LEN]);
void incremental_copy(store_t *store, store_t *dst_store, const char *filepath, void incremental_copy(store_t *store, store_t *dst_store, const char *filepath,
const char *dst_filepath, GHashTable *copy_table); const char *dst_filepath, GHashTable *copy_table);
@ -24,7 +24,7 @@ void write_document(document_t *doc);
void read_lines(const char *path, const line_processor_t processor); void read_lines(const char *path, const line_processor_t processor);
void read_index(const char *path, const char[MD5_STR_LENGTH], const char *type, index_func); void read_index(const char *path, const char index_id[SIST_INDEX_ID_LEN], const char *type, index_func);
void incremental_read(GHashTable *table, const char *filepath, index_descriptor_t *desc); void incremental_read(GHashTable *table, const char *filepath, index_descriptor_t *desc);

View File

@ -52,22 +52,7 @@ void store_flush(store_t *store) {
void store_write(store_t *store, char *key, size_t key_len, char *buf, size_t buf_len) { void store_write(store_t *store, char *key, size_t key_len, char *buf, size_t buf_len) {
if (LogCtx.very_verbose) { if (LogCtx.very_verbose) {
if (key_len == MD5_DIGEST_LENGTH) { LOG_DEBUGF("store.c", "Store write %s@{%s} %lu bytes", store->path, key, buf_len)
char path_md5_str[MD5_STR_LENGTH];
buf2hex((unsigned char *) key, MD5_DIGEST_LENGTH, path_md5_str);
LOG_DEBUGF("store.c", "Store write {%s} %lu bytes", path_md5_str, buf_len)
} else if (key_len == MD5_DIGEST_LENGTH + sizeof(int)) {
char path_md5_str[MD5_STR_LENGTH];
buf2hex((unsigned char *) key, MD5_DIGEST_LENGTH, path_md5_str);
LOG_DEBUGF("store.c", "Store write {%s/%d} %lu bytes",
path_md5_str, *(int *) (key + MD5_DIGEST_LENGTH), buf_len);
} else {
LOG_DEBUGF("store.c", "Store write {%s} %lu bytes", key, buf_len)
}
} }
#if (SIST_FAKE_STORE != 1) #if (SIST_FAKE_STORE != 1)

View File

@ -22,7 +22,7 @@ parse_job_t *create_fs_parse_job(const char *filepath, const struct stat *info,
job->vfile.info = *info; job->vfile.info = *info;
memset(job->parent, 0, MD5_DIGEST_LENGTH); job->parent[0] = '\0';
job->vfile.filepath = job->filepath; job->vfile.filepath = job->filepath;
job->vfile.read = fs_read; job->vfile.read = fs_read;

View File

@ -118,7 +118,7 @@ void init_dir(const char *dirpath, scan_args_t* args) {
index_descriptor_t original_desc = read_index_descriptor(descriptor_path); index_descriptor_t original_desc = read_index_descriptor(descriptor_path);
memcpy(ScanCtx.index.desc.id, original_desc.id, sizeof(original_desc.id)); memcpy(ScanCtx.index.desc.id, original_desc.id, sizeof(original_desc.id));
} else { } else {
// genreate new index id based on timestamp // generate new index id based on timestamp
unsigned char index_md5[MD5_DIGEST_LENGTH]; unsigned char index_md5[MD5_DIGEST_LENGTH];
MD5((unsigned char *) &ScanCtx.index.desc.timestamp, sizeof(ScanCtx.index.desc.timestamp), index_md5); MD5((unsigned char *) &ScanCtx.index.desc.timestamp, sizeof(ScanCtx.index.desc.timestamp), index_md5);
buf2hex(index_md5, MD5_DIGEST_LENGTH, ScanCtx.index.desc.id); buf2hex(index_md5, MD5_DIGEST_LENGTH, ScanCtx.index.desc.id);

View File

@ -69,7 +69,7 @@ void parse(void *arg) {
doc->base = (short) job->base; doc->base = (short) job->base;
char *rel_path = doc->filepath + ScanCtx.index.desc.root_len; char *rel_path = doc->filepath + ScanCtx.index.desc.root_len;
MD5((unsigned char *) rel_path, strlen(rel_path), doc->path_md5); generate_doc_id(rel_path, doc->doc_id);
doc->meta_head = NULL; doc->meta_head = NULL;
doc->meta_tail = NULL; doc->meta_tail = NULL;
@ -77,10 +77,10 @@ void parse(void *arg) {
doc->size = job->vfile.info.st_size; doc->size = job->vfile.info.st_size;
doc->mtime = (int) job->vfile.info.st_mtim.tv_sec; doc->mtime = (int) job->vfile.info.st_mtim.tv_sec;
int inc_ts = incremental_get(ScanCtx.original_table, doc->path_md5); int inc_ts = incremental_get(ScanCtx.original_table, doc->doc_id);
if (inc_ts != 0 && inc_ts == job->vfile.info.st_mtim.tv_sec) { if (inc_ts != 0 && inc_ts == job->vfile.info.st_mtim.tv_sec) {
pthread_mutex_lock(&ScanCtx.copy_table_mu); pthread_mutex_lock(&ScanCtx.copy_table_mu);
incremental_mark_file(ScanCtx.copy_table, doc->path_md5); incremental_mark_file(ScanCtx.copy_table, doc->doc_id);
pthread_mutex_unlock(&ScanCtx.copy_table_mu); pthread_mutex_unlock(&ScanCtx.copy_table_mu);
pthread_mutex_lock(&ScanCtx.dbg_file_counts_mu); pthread_mutex_lock(&ScanCtx.dbg_file_counts_mu);
@ -96,16 +96,14 @@ void parse(void *arg) {
if (ScanCtx.new_table != NULL) { if (ScanCtx.new_table != NULL) {
pthread_mutex_lock(&ScanCtx.copy_table_mu); pthread_mutex_lock(&ScanCtx.copy_table_mu);
incremental_mark_file(ScanCtx.new_table, doc->path_md5); incremental_mark_file(ScanCtx.new_table, doc->doc_id);
pthread_mutex_unlock(&ScanCtx.copy_table_mu); pthread_mutex_unlock(&ScanCtx.copy_table_mu);
} }
char *buf[MAGIC_BUF_SIZE]; char *buf[MAGIC_BUF_SIZE];
if (LogCtx.very_verbose) { if (LogCtx.very_verbose) {
char path_md5_str[MD5_STR_LENGTH]; LOG_DEBUGF(job->filepath, "Starting parse job {%s}", doc->doc_id)
buf2hex(doc->path_md5, MD5_DIGEST_LENGTH, path_md5_str);
LOG_DEBUGF(job->filepath, "Starting parse job {%s}", path_md5_str)
} }
if (job->vfile.info.st_size == 0) { if (job->vfile.info.st_size == 0) {
@ -218,10 +216,10 @@ void parse(void *arg) {
abort: abort:
//Parent meta //Parent meta
if (!md5_digest_is_null(job->parent)) { if (job->parent[0] != '\0') {
meta_line_t *meta_parent = malloc(sizeof(meta_line_t) + MD5_STR_LENGTH); meta_line_t *meta_parent = malloc(sizeof(meta_line_t) + SIST_INDEX_ID_LEN);
meta_parent->key = MetaParent; meta_parent->key = MetaParent;
buf2hex(job->parent, MD5_DIGEST_LENGTH, meta_parent->str_val); strcpy(meta_parent->str_val, job->parent);
APPEND_META((doc), meta_parent) APPEND_META((doc), meta_parent)
doc->has_parent = TRUE; doc->has_parent = TRUE;

View File

@ -23,14 +23,17 @@ void parse_sidecar(vfile_t *vfile, document_t *doc) {
} }
char *json_str = cJSON_PrintUnformatted(json); char *json_str = cJSON_PrintUnformatted(json);
unsigned char path_md5[MD5_DIGEST_LENGTH]; char assoc_doc_id[SIST_DOC_ID_LEN];
MD5((unsigned char *) vfile->filepath + ScanCtx.index.desc.root_len, doc->ext - 1 - ScanCtx.index.desc.root_len,
path_md5);
char path_md5_str[MD5_STR_LENGTH]; char rel_path[PATH_MAX];
buf2hex(path_md5, MD5_DIGEST_LENGTH, path_md5_str); size_t rel_path_len = doc->ext - 1 - ScanCtx.index.desc.root_len;
memcpy(rel_path, vfile->filepath + ScanCtx.index.desc.root_len, rel_path_len);
*(rel_path + rel_path_len) = '\0';
store_write(ScanCtx.index.meta_store, path_md5_str, MD5_STR_LENGTH, json_str, strlen(json_str) + 1); generate_doc_id(rel_path, assoc_doc_id);
store_write(ScanCtx.index.meta_store, assoc_doc_id, sizeof(assoc_doc_id), json_str,
strlen(json_str) + 1);
cJSON_Delete(json); cJSON_Delete(json);
free(json_str); free(json_str);

View File

@ -53,14 +53,14 @@
#include <ctype.h> #include <ctype.h>
#include "git_hash.h" #include "git_hash.h"
#define VERSION "2.11.7" #define VERSION "2.12.0"
static const char *const Version = VERSION; static const char *const Version = VERSION;
#ifndef SIST_PLATFORM #ifndef SIST_PLATFORM
#define SIST_PLATFORM unknown #define SIST_PLATFORM unknown
#endif #endif
#define EXPECTED_MONGOOSE_VERSION "7.3" #define EXPECTED_MONGOOSE_VERSION "7.6"
#define Q(x) #x #define Q(x) #x
#define QUOTE(x) Q(x) #define QUOTE(x) Q(x)

View File

@ -20,7 +20,7 @@ typedef struct {
long count; long count;
} agg_t; } agg_t;
void fill_tables(cJSON *document, UNUSED(const char index_id[MD5_STR_LENGTH])) { void fill_tables(cJSON *document, UNUSED(const char index_id[SIST_INDEX_ID_LEN])) {
if (cJSON_GetObjectItem(document, "parent") != NULL) { if (cJSON_GetObjectItem(document, "parent") != NULL) {
return; return;

View File

@ -4,7 +4,7 @@
#define INDEX_TYPE_NDJSON "ndjson" #define INDEX_TYPE_NDJSON "ndjson"
typedef struct index_descriptor { typedef struct index_descriptor {
char id[MD5_STR_LENGTH]; char id[SIST_INDEX_ID_LEN];
char version[64]; char version[64];
long timestamp; long timestamp;
char root[PATH_MAX]; char root[PATH_MAX];

View File

@ -10,8 +10,6 @@
#include "third-party/utf8.h/utf8.h" #include "third-party/utf8.h/utf8.h"
#include "libscan/scan.h" #include "libscan/scan.h"
#define MD5_STR_LENGTH 33
char *abspath(const char *path); char *abspath(const char *path);
@ -94,40 +92,24 @@ static void buf2hex(const unsigned char *buf, size_t buflen, char *hex_string) {
__always_inline __always_inline
static int md5_digest_is_null(const unsigned char digest[MD5_DIGEST_LENGTH]) { static void generate_doc_id(const char *rel_path, char *doc_id) {
return (*(int64_t *) digest) == 0 && (*((int64_t *) digest + 1)) == 0; unsigned char md[MD5_DIGEST_LENGTH];
MD5((unsigned char *) rel_path, strlen(rel_path), md);
buf2hex(md, sizeof(md), doc_id);
} }
__always_inline __always_inline
static void incremental_put(GHashTable *table, const unsigned char path_md5[MD5_DIGEST_LENGTH], int mtime) { static void incremental_put(GHashTable *table, const char doc_id[SIST_DOC_ID_LEN], int mtime) {
char *ptr = malloc(MD5_STR_LENGTH); char *ptr = malloc(SIST_DOC_ID_LEN);
buf2hex(path_md5, MD5_DIGEST_LENGTH, ptr); strcpy(ptr, doc_id);
g_hash_table_insert(table, ptr, GINT_TO_POINTER(mtime)); g_hash_table_insert(table, ptr, GINT_TO_POINTER(mtime));
} }
__always_inline __always_inline
static void incremental_put_str(GHashTable *table, const char *path_md5, int mtime) { static int incremental_get(GHashTable *table, const char doc_id[SIST_DOC_ID_LEN]) {
char *ptr = malloc(MD5_STR_LENGTH);
strcpy(ptr, path_md5);
g_hash_table_insert(table, ptr, GINT_TO_POINTER(mtime));
}
__always_inline
static int incremental_get(GHashTable *table, const unsigned char path_md5[MD5_DIGEST_LENGTH]) {
if (table != NULL) { if (table != NULL) {
char md5_str[MD5_STR_LENGTH]; return GPOINTER_TO_INT(g_hash_table_lookup(table, doc_id));
buf2hex(path_md5, MD5_DIGEST_LENGTH, md5_str);
return GPOINTER_TO_INT(g_hash_table_lookup(table, md5_str));
} else {
return 0;
}
}
__always_inline
static int incremental_get_str(GHashTable *table, const char *path_md5) {
if (table != NULL) {
return GPOINTER_TO_INT(g_hash_table_lookup(table, path_md5));
} else { } else {
return 0; return 0;
} }
@ -138,9 +120,9 @@ static int incremental_get_str(GHashTable *table, const char *path_md5) {
* !!Not thread safe. * !!Not thread safe.
*/ */
__always_inline __always_inline
static int incremental_mark_file(GHashTable *table, const unsigned char path_md5[MD5_DIGEST_LENGTH]) { static int incremental_mark_file(GHashTable *table, const char doc_id[SIST_DOC_ID_LEN]) {
char *ptr = malloc(MD5_STR_LENGTH); char *ptr = malloc(SIST_DOC_ID_LEN);
buf2hex(path_md5, MD5_DIGEST_LENGTH, ptr); strcpy(ptr, doc_id);
return g_hash_table_insert(table, ptr, GINT_TO_POINTER(1)); return g_hash_table_insert(table, ptr, GINT_TO_POINTER(1));
} }

View File

@ -12,6 +12,13 @@
#define HTTP_TEXT_TYPE_HEADER "Content-Type: text/plain;charset=utf-8\r\n" #define HTTP_TEXT_TYPE_HEADER "Content-Type: text/plain;charset=utf-8\r\n"
#define HTTP_REPLY_NOT_FOUND mg_http_reply(nc, 404, HTTP_SERVER_HEADER HTTP_TEXT_TYPE_HEADER, "Not found"); #define HTTP_REPLY_NOT_FOUND mg_http_reply(nc, 404, HTTP_SERVER_HEADER HTTP_TEXT_TYPE_HEADER, "Not found");
static struct mg_http_serve_opts DefaultServeOpts = {
.fs = NULL,
.ssi_pattern = NULL,
.root_dir = NULL,
.mime_types = ""
};
static void send_response_line(struct mg_connection *nc, int status_code, size_t length, char *extra_headers) { static void send_response_line(struct mg_connection *nc, int status_code, size_t length, char *extra_headers) {
mg_printf( mg_printf(
@ -29,7 +36,7 @@ static void send_response_line(struct mg_connection *nc, int status_code, size_t
index_t *get_index_by_id(const char *index_id) { index_t *get_index_by_id(const char *index_id) {
for (int i = WebCtx.index_count; i >= 0; i--) { for (int i = WebCtx.index_count; i >= 0; i--) {
if (strncmp(index_id, WebCtx.indices[i].desc.id, MD5_STR_LENGTH) == 0) { if (strncmp(index_id, WebCtx.indices[i].desc.id, SIST_INDEX_ID_LEN) == 0) {
return &WebCtx.indices[i]; return &WebCtx.indices[i];
} }
} }
@ -54,7 +61,7 @@ store_t *get_tag_store(const char *index_id) {
void search_index(struct mg_connection *nc, struct mg_http_message *hm) { void search_index(struct mg_connection *nc, struct mg_http_message *hm) {
if (WebCtx.dev) { if (WebCtx.dev) {
mg_http_serve_file(nc, hm, "sist2-vue/dist/index.html", "text/html", NULL); mg_http_serve_file(nc, hm, "sist2-vue/dist/index.html", &DefaultServeOpts);
} else { } else {
send_response_line(nc, 200, sizeof(index_html), "Content-Type: text/html"); send_response_line(nc, 200, sizeof(index_html), "Content-Type: text/html");
mg_send(nc, index_html, sizeof(index_html)); mg_send(nc, index_html, sizeof(index_html));
@ -63,23 +70,23 @@ void search_index(struct mg_connection *nc, struct mg_http_message *hm) {
void stats_files(struct mg_connection *nc, struct mg_http_message *hm) { void stats_files(struct mg_connection *nc, struct mg_http_message *hm) {
if (hm->uri.len != MD5_STR_LENGTH + 4) { if (hm->uri.len != SIST_INDEX_ID_LEN + 4) {
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
char arg_md5[MD5_STR_LENGTH]; char arg_index_id[SIST_INDEX_ID_LEN];
memcpy(arg_md5, hm->uri.ptr + 3, MD5_STR_LENGTH); memcpy(arg_index_id, hm->uri.ptr + 3, SIST_INDEX_ID_LEN);
*(arg_md5 + MD5_STR_LENGTH - 1) = '\0'; *(arg_index_id + SIST_INDEX_ID_LEN - 1) = '\0';
index_t *index = get_index_by_id(arg_md5); index_t *index = get_index_by_id(arg_index_id);
if (index == NULL) { if (index == NULL) {
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
const char *file; const char *file;
switch (atoi(hm->uri.ptr + 3 + MD5_STR_LENGTH)) { switch (atoi(hm->uri.ptr + 3 + SIST_INDEX_ID_LEN)) {
case 1: case 1:
file = "treemap.csv"; file = "treemap.csv";
break; break;
@ -104,12 +111,13 @@ void stats_files(struct mg_connection *nc, struct mg_http_message *hm) {
strcpy(full_path, index->path); strcpy(full_path, index->path);
strcat(full_path, file); strcat(full_path, file);
mg_http_serve_file(nc, hm, full_path, "text/csv", disposition); struct mg_http_serve_opts opts = {};
mg_http_serve_file(nc, hm, full_path, &opts);
} }
void javascript(struct mg_connection *nc, struct mg_http_message *hm) { void javascript(struct mg_connection *nc, struct mg_http_message *hm) {
if (WebCtx.dev) { if (WebCtx.dev) {
mg_http_serve_file(nc, hm, "sist2-vue/dist/js/index.js", "application/javascript", NULL); mg_http_serve_file(nc, hm, "sist2-vue/dist/js/index.js", &DefaultServeOpts);
} else { } else {
send_response_line(nc, 200, sizeof(index_js), "Content-Type: application/javascript"); send_response_line(nc, 200, sizeof(index_js), "Content-Type: application/javascript");
mg_send(nc, index_js, sizeof(index_js)); mg_send(nc, index_js, sizeof(index_js));
@ -118,7 +126,7 @@ void javascript(struct mg_connection *nc, struct mg_http_message *hm) {
void javascript_vendor(struct mg_connection *nc, struct mg_http_message *hm) { void javascript_vendor(struct mg_connection *nc, struct mg_http_message *hm) {
if (WebCtx.dev) { if (WebCtx.dev) {
mg_http_serve_file(nc, hm, "sist2-vue/dist/js/chunk-vendors.js", "application/javascript", NULL); mg_http_serve_file(nc, hm, "sist2-vue/dist/js/chunk-vendors.js", &DefaultServeOpts);
} else { } else {
send_response_line(nc, 200, sizeof(chunk_vendors_js), "Content-Type: application/javascript"); send_response_line(nc, 200, sizeof(chunk_vendors_js), "Content-Type: application/javascript");
mg_send(nc, chunk_vendors_js, sizeof(chunk_vendors_js)); mg_send(nc, chunk_vendors_js, sizeof(chunk_vendors_js));
@ -142,28 +150,25 @@ void style_vendor(struct mg_connection *nc, struct mg_http_message *hm) {
void thumbnail(struct mg_connection *nc, struct mg_http_message *hm) { void thumbnail(struct mg_connection *nc, struct mg_http_message *hm) {
int parse_tn_num = FALSE; int has_thumbnail_index = FALSE;
if (hm->uri.len != 68) { if (hm->uri.len != SIST_INDEX_ID_LEN + SIST_DOC_ID_LEN + 2) {
if (hm->uri.len != 68 + 4) { if (hm->uri.len != SIST_INDEX_ID_LEN + SIST_DOC_ID_LEN + 2 + 4) {
LOG_DEBUGF("serve.c", "Invalid thumbnail path: %.*s", (int) hm->uri.len, hm->uri.ptr) LOG_DEBUGF("serve.c", "Invalid thumbnail path: %.*s", (int) hm->uri.len, hm->uri.ptr)
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
parse_tn_num = TRUE; has_thumbnail_index = TRUE;
} }
char arg_file_md5[MD5_STR_LENGTH]; char arg_doc_id[SIST_DOC_ID_LEN];
char arg_index[MD5_STR_LENGTH]; char arg_index[SIST_INDEX_ID_LEN];
memcpy(arg_index, hm->uri.ptr + 3, MD5_STR_LENGTH); memcpy(arg_index, hm->uri.ptr + 3, SIST_INDEX_ID_LEN);
*(arg_index + MD5_STR_LENGTH - 1) = '\0'; *(arg_index + SIST_INDEX_ID_LEN - 1) = '\0';
memcpy(arg_file_md5, hm->uri.ptr + 3 + MD5_STR_LENGTH, MD5_STR_LENGTH); memcpy(arg_doc_id, hm->uri.ptr + 3 + SIST_INDEX_ID_LEN, SIST_DOC_ID_LEN);
*(arg_file_md5 + MD5_STR_LENGTH - 1) = '\0'; *(arg_doc_id + SIST_DOC_ID_LEN - 1) = '\0';
unsigned char md5_buf[MD5_DIGEST_LENGTH];
hex2buf(arg_file_md5, MD5_STR_LENGTH - 1, md5_buf);
store_t *store = get_store(arg_index); store_t *store = get_store(arg_index);
if (store == NULL) { if (store == NULL) {
@ -175,16 +180,17 @@ void thumbnail(struct mg_connection *nc, struct mg_http_message *hm) {
char *data; char *data;
size_t data_len = 0; size_t data_len = 0;
if (parse_tn_num) { if (has_thumbnail_index) {
int tn_num = atoi(hm->uri.ptr + 68); const char *tn_index = hm->uri.ptr + SIST_INDEX_ID_LEN + SIST_DOC_ID_LEN + 2;
char tn_key[sizeof(md5_buf) + sizeof(int)]; char tn_key[sizeof(arg_doc_id) + sizeof(char) * 4];
memcpy(tn_key, md5_buf, sizeof(md5_buf));
memcpy(tn_key + sizeof(md5_buf), &tn_num, sizeof(tn_num)); memcpy(tn_key, arg_doc_id, sizeof(arg_doc_id));
memcpy(tn_key + sizeof(arg_doc_id) - 1, tn_index, sizeof(char) * 4);
data = store_read(store, (char *) tn_key, sizeof(tn_key), &data_len); data = store_read(store, (char *) tn_key, sizeof(tn_key), &data_len);
} else { } else {
data = store_read(store, (char *) md5_buf, sizeof(md5_buf), &data_len); data = store_read(store, (char *) arg_doc_id, sizeof(arg_doc_id), &data_len);
} }
if (data_len != 0) { if (data_len != 0) {
@ -274,10 +280,18 @@ void serve_file_from_disk(cJSON *json, index_t *idx, struct mg_connection *nc, s
char disposition[8192]; char disposition[8192];
snprintf(disposition, sizeof(disposition), snprintf(disposition, sizeof(disposition),
HTTP_SERVER_HEADER "Content-Disposition: inline; filename=\"%s%s%s\"\r\nAccept-Ranges: bytes\r\n", HTTP_SERVER_HEADER "Content-Disposition: inline; filename=\"%s%s%s\"\r\n"
"Accept-Ranges: bytes\r\nCache-Control: no-store\r\n",
name, strlen(ext) == 0 ? "" : ".", ext); name, strlen(ext) == 0 ? "" : ".", ext);
mg_http_serve_file(nc, hm, full_path, mime, disposition); char mime_mapping[1024];
snprintf(mime_mapping, sizeof(mime_mapping), "%s=%s", ext, mime);
struct mg_http_serve_opts opts = {
.extra_headers = disposition,
.mime_types = mime_mapping
};
mg_http_serve_file(nc, hm, full_path, &opts);
} }
void cache_es_version() { void cache_es_version() {
@ -341,17 +355,17 @@ void index_info(struct mg_connection *nc) {
void document_info(struct mg_connection *nc, struct mg_http_message *hm) { void document_info(struct mg_connection *nc, struct mg_http_message *hm) {
if (hm->uri.len != MD5_STR_LENGTH + 2) { if (hm->uri.len != SIST_DOC_ID_LEN + 2) {
LOG_DEBUGF("serve.c", "Invalid document_info path: %.*s", (int) hm->uri.len, hm->uri.ptr) LOG_DEBUGF("serve.c", "Invalid document_info path: %.*s", (int) hm->uri.len, hm->uri.ptr)
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
char arg_md5[MD5_STR_LENGTH]; char arg_doc_id[SIST_DOC_ID_LEN];
memcpy(arg_md5, hm->uri.ptr + 3, MD5_STR_LENGTH); memcpy(arg_doc_id, hm->uri.ptr + 3, SIST_DOC_ID_LEN);
*(arg_md5 + MD5_STR_LENGTH - 1) = '\0'; *(arg_doc_id + SIST_DOC_ID_LEN - 1) = '\0';
cJSON *doc = elastic_get_document(arg_md5); cJSON *doc = elastic_get_document(arg_doc_id);
cJSON *source = cJSON_GetObjectItem(doc, "_source"); cJSON *source = cJSON_GetObjectItem(doc, "_source");
cJSON *index_id = cJSON_GetObjectItem(source, "index"); cJSON *index_id = cJSON_GetObjectItem(source, "index");
@ -377,17 +391,17 @@ void document_info(struct mg_connection *nc, struct mg_http_message *hm) {
void file(struct mg_connection *nc, struct mg_http_message *hm) { void file(struct mg_connection *nc, struct mg_http_message *hm) {
if (hm->uri.len != MD5_STR_LENGTH + 2) { if (hm->uri.len != SIST_DOC_ID_LEN + 2) {
LOG_DEBUGF("serve.c", "Invalid file path: %.*s", (int) hm->uri.len, hm->uri.ptr) LOG_DEBUGF("serve.c", "Invalid file path: %.*s", (int) hm->uri.len, hm->uri.ptr)
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
char arg_md5[MD5_STR_LENGTH]; char arg_doc_id[SIST_DOC_ID_LEN];
memcpy(arg_md5, hm->uri.ptr + 3, MD5_STR_LENGTH); memcpy(arg_doc_id, hm->uri.ptr + 3, SIST_DOC_ID_LEN);
*(arg_md5 + MD5_STR_LENGTH - 1) = '\0'; *(arg_doc_id + SIST_DOC_ID_LEN - 1) = '\0';
const char *next = arg_md5; const char *next = arg_doc_id;
cJSON *doc = NULL; cJSON *doc = NULL;
cJSON *index_id = NULL; cJSON *index_id = NULL;
cJSON *source = NULL; cJSON *source = NULL;
@ -438,7 +452,6 @@ void status(struct mg_connection *nc) {
typedef struct { typedef struct {
char *name; char *name;
int delete; int delete;
char *path_md5_str;
char *doc_id; char *doc_id;
} tag_req_t; } tag_req_t;
@ -458,12 +471,6 @@ tag_req_t *parse_tag_request(cJSON *json) {
return NULL; return NULL;
} }
cJSON *arg_path_md5 = cJSON_GetObjectItem(json, "path_md5");
if (arg_path_md5 == NULL || !cJSON_IsString(arg_path_md5) ||
strlen(arg_path_md5->valuestring) != MD5_STR_LENGTH - 1) {
return NULL;
}
cJSON *arg_doc_id = cJSON_GetObjectItem(json, "doc_id"); cJSON *arg_doc_id = cJSON_GetObjectItem(json, "doc_id");
if (arg_doc_id == NULL || !cJSON_IsString(arg_doc_id)) { if (arg_doc_id == NULL || !cJSON_IsString(arg_doc_id)) {
return NULL; return NULL;
@ -472,22 +479,21 @@ tag_req_t *parse_tag_request(cJSON *json) {
tag_req_t *req = malloc(sizeof(tag_req_t)); tag_req_t *req = malloc(sizeof(tag_req_t));
req->delete = arg_delete->valueint; req->delete = arg_delete->valueint;
req->name = arg_name->valuestring; req->name = arg_name->valuestring;
req->path_md5_str = arg_path_md5->valuestring;
req->doc_id = arg_doc_id->valuestring; req->doc_id = arg_doc_id->valuestring;
return req; return req;
} }
void tag(struct mg_connection *nc, struct mg_http_message *hm) { void tag(struct mg_connection *nc, struct mg_http_message *hm) {
if (hm->uri.len != MD5_STR_LENGTH + 4) { if (hm->uri.len != SIST_INDEX_ID_LEN + 4) {
LOG_DEBUGF("serve.c", "Invalid tag path: %.*s", (int) hm->uri.len, hm->uri.ptr) LOG_DEBUGF("serve.c", "Invalid tag path: %.*s", (int) hm->uri.len, hm->uri.ptr)
HTTP_REPLY_NOT_FOUND HTTP_REPLY_NOT_FOUND
return; return;
} }
char arg_index[MD5_STR_LENGTH]; char arg_index[SIST_INDEX_ID_LEN];
memcpy(arg_index, hm->uri.ptr + 5, MD5_STR_LENGTH); memcpy(arg_index, hm->uri.ptr + 5, SIST_INDEX_ID_LEN);
*(arg_index + MD5_STR_LENGTH - 1) = '\0'; *(arg_index + SIST_INDEX_ID_LEN - 1) = '\0';
if (hm->body.len < 2 || hm->method.len != 4 || memcmp(&hm->method, "POST", 4) == 0) { if (hm->body.len < 2 || hm->method.len != 4 || memcmp(&hm->method, "POST", 4) == 0) {
LOG_DEBUG("serve.c", "Invalid tag request") LOG_DEBUG("serve.c", "Invalid tag request")
@ -519,7 +525,7 @@ void tag(struct mg_connection *nc, struct mg_http_message *hm) {
cJSON *arr = NULL; cJSON *arr = NULL;
size_t data_len = 0; size_t data_len = 0;
const char *data = store_read(store, arg_req->path_md5_str, MD5_STR_LENGTH, &data_len); const char *data = store_read(store, arg_req->doc_id, SIST_DOC_ID_LEN, &data_len);
if (data_len == 0) { if (data_len == 0) {
arr = cJSON_CreateArray(); arr = cJSON_CreateArray();
} else { } else {
@ -579,7 +585,7 @@ void tag(struct mg_connection *nc, struct mg_http_message *hm) {
} }
char *json_str = cJSON_PrintUnformatted(arr); char *json_str = cJSON_PrintUnformatted(arr);
store_write(store, arg_req->path_md5_str, MD5_STR_LENGTH, json_str, strlen(json_str) + 1); store_write(store, arg_req->doc_id, SIST_DOC_ID_LEN, json_str, strlen(json_str) + 1);
store_flush(store); store_flush(store);
free(arg_req); free(arg_req);

File diff suppressed because one or more lines are too long

View File

@ -6,26 +6,6 @@ set(CMAKE_C_STANDARD 11)
option(BUILD_TESTS "Build tests" on) option(BUILD_TESTS "Build tests" on)
add_subdirectory(third-party/antiword) add_subdirectory(third-party/antiword)
if (SIST_DEBUG)
add_compile_definitions(
antiword
DEBUG
)
target_compile_options(
antiword
PRIVATE
-g
-fstack-protector
-fno-omit-frame-pointer
-fsanitize=address
-fno-inline
)
else()
add_compile_definitions(
antiword
NDEBUG
)
endif()
add_library( add_library(
scan scan
@ -48,6 +28,38 @@ add_library(
libscan/mobi/scan_mobi.c libscan/mobi/scan_mobi.h libscan/raw/raw.c libscan/raw/raw.h) libscan/mobi/scan_mobi.c libscan/mobi/scan_mobi.h libscan/raw/raw.c libscan/raw/raw.h)
set_target_properties(scan PROPERTIES LINKER_LANGUAGE C) set_target_properties(scan PROPERTIES LINKER_LANGUAGE C)
if (SIST_DEBUG)
add_compile_definitions(
antiword
DEBUG
)
target_compile_options(
antiword
PRIVATE
-g
-fstack-protector
-fno-omit-frame-pointer
-fsanitize=address
-fno-inline
)
else()
add_compile_definitions(
antiword
NDEBUG
)
target_compile_options(
scan
PRIVATE
-Ofast
#-march=native
-fno-stack-protector
-fomit-frame-pointer
#-freciprocal-math
)
endif()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib .so) set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib .so)
find_package(cJSON CONFIG REQUIRED) find_package(cJSON CONFIG REQUIRED)

View File

@ -202,7 +202,7 @@ scan_code_t parse_archive(scan_arc_ctx_t *ctx, vfile_t *f, document_t *doc, pcre
sub_job->vfile.logf = ctx->logf; sub_job->vfile.logf = ctx->logf;
sub_job->vfile.has_checksum = FALSE; sub_job->vfile.has_checksum = FALSE;
sub_job->vfile.calculate_checksum = f->calculate_checksum; sub_job->vfile.calculate_checksum = f->calculate_checksum;
memcpy(sub_job->parent, doc->path_md5, MD5_DIGEST_LENGTH); strcpy(sub_job->parent, doc->doc_id);
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
sub_job->vfile.info = *archive_entry_stat(entry); sub_job->vfile.info = *archive_entry_stat(entry);

View File

@ -156,7 +156,7 @@ int render_cover(scan_ebook_ctx_t *ctx, fz_context *fzctx, document_t *doc, fz_d
avcodec_receive_packet(jpeg_encoder, &jpeg_packet); avcodec_receive_packet(jpeg_encoder, &jpeg_packet);
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) jpeg_packet.data, jpeg_packet.size); ctx->store(doc->doc_id, sizeof(doc->doc_id), (char *) jpeg_packet.data, jpeg_packet.size);
free(samples); free(samples);
av_packet_unref(&jpeg_packet); av_packet_unref(&jpeg_packet);

View File

@ -232,7 +232,7 @@ void parse_font(scan_font_ctx_t *ctx, vfile_t *f, document_t *doc) {
bmp_format(&bmp_data, dimensions, bitmap); bmp_format(&bmp_data, dimensions, bitmap);
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) bmp_data.buf, bmp_data.cur); ctx->store(doc->doc_id, sizeof(doc->doc_id), (char *) bmp_data.buf, bmp_data.cur);
dyn_buffer_destroy(&bmp_data); dyn_buffer_destroy(&bmp_data);
free(bitmap); free(bitmap);

View File

@ -459,7 +459,7 @@ int decode_frame_and_save_thumbnail(scan_media_ctx_t *ctx, AVFormatContext *pFor
if (scaled_frame == STORE_AS_IS) { if (scaled_frame == STORE_AS_IS) {
return_value = SAVE_THUMBNAIL_OK; return_value = SAVE_THUMBNAIL_OK;
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) frame_and_packet->packet->data, ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), (char *) frame_and_packet->packet->data,
frame_and_packet->packet->size); frame_and_packet->packet->size);
} else { } else {
// Encode frame to jpeg // Encode frame to jpeg
@ -473,7 +473,7 @@ int decode_frame_and_save_thumbnail(scan_media_ctx_t *ctx, AVFormatContext *pFor
// Save thumbnail // Save thumbnail
if (thumbnail_index == 0) { if (thumbnail_index == 0) {
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) jpeg_packet.data, jpeg_packet.size); ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), (char *) jpeg_packet.data, jpeg_packet.size);
return_value = SAVE_THUMBNAIL_OK; return_value = SAVE_THUMBNAIL_OK;
} else if (thumbnail_index > 1) { } else if (thumbnail_index > 1) {
@ -482,9 +482,8 @@ int decode_frame_and_save_thumbnail(scan_media_ctx_t *ctx, AVFormatContext *pFor
// I figure out a better fix. // I figure out a better fix.
thumbnail_index -= 1; thumbnail_index -= 1;
char tn_key[sizeof(doc->path_md5) + sizeof(int)]; char tn_key[sizeof(doc->doc_id) + sizeof(char) * 4];
memcpy(tn_key, doc->path_md5, sizeof(doc->path_md5)); snprintf(tn_key, sizeof(tn_key), "%s%04d", doc->doc_id, thumbnail_index);
memcpy(tn_key + sizeof(doc->path_md5), &thumbnail_index, sizeof(thumbnail_index));
ctx->store((char *) tn_key, sizeof(tn_key), (char *) jpeg_packet.data, jpeg_packet.size); ctx->store((char *) tn_key, sizeof(tn_key), (char *) jpeg_packet.data, jpeg_packet.size);
} else { } else {
@ -579,8 +578,8 @@ void parse_media_format_ctx(scan_media_ctx_t *ctx, AVFormatContext *pFormatCtx,
int video_duration_in_seconds = (int) (pFormatCtx->duration / AV_TIME_BASE); int video_duration_in_seconds = (int) (pFormatCtx->duration / AV_TIME_BASE);
int thumbnails_to_generate = (IS_VIDEO(pFormatCtx) && stream->codecpar->codec_id != AV_CODEC_ID_GIF && video_duration_in_seconds >= 15) int thumbnails_to_generate = (IS_VIDEO(pFormatCtx) && stream->codecpar->codec_id != AV_CODEC_ID_GIF && video_duration_in_seconds >= 15)
// Limit to ~1 thumbnail every 5s // Limit to ~1 thumbnail every 7s
? MAX(MIN(ctx->tn_count, video_duration_in_seconds / 5 + 1), 1) + 1 ? MAX(MIN(ctx->tn_count, video_duration_in_seconds / 7 + 1), 1) + 1
: 1; : 1;
const double seek_increment = thumbnails_to_generate == 1 const double seek_increment = thumbnails_to_generate == 1
@ -845,7 +844,7 @@ int store_image_thumbnail(scan_media_ctx_t *ctx, void *buf, size_t buf_len, docu
if (scaled_frame == STORE_AS_IS) { if (scaled_frame == STORE_AS_IS) {
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) frame_and_packet->packet->data, ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), (char *) frame_and_packet->packet->data,
frame_and_packet->packet->size); frame_and_packet->packet->size);
} else { } else {
// Encode frame to jpeg // Encode frame to jpeg
@ -859,7 +858,7 @@ int store_image_thumbnail(scan_media_ctx_t *ctx, void *buf, size_t buf_len, docu
// Save thumbnail // Save thumbnail
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) jpeg_packet.data, jpeg_packet.size); ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), (char *) jpeg_packet.data, jpeg_packet.size);
av_packet_unref(&jpeg_packet); av_packet_unref(&jpeg_packet);
avcodec_free_context(&jpeg_encoder); avcodec_free_context(&jpeg_encoder);

View File

@ -191,7 +191,7 @@ void read_thumbnail(scan_ooxml_ctx_t *ctx, document_t *doc, struct archive *a, s
archive_read_data(a, buf, entry_size); archive_read_data(a, buf, entry_size);
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), buf, entry_size); ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), buf, entry_size);
free(buf); free(buf);
} }

View File

@ -7,8 +7,22 @@
#define MIN_SIZE 32 #define MIN_SIZE 32
int store_thumbnail_jpeg(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, document_t *doc) { int store_thumbnail_jpeg(scan_raw_ctx_t *ctx, libraw_thumbnail_t img, document_t *doc) {
return store_image_thumbnail((scan_media_ctx_t *) ctx, img->data, img->data_size, doc, "x.jpeg");
scan_media_ctx_t media_ctx = {
.read_subtitles = FALSE,
.tn_count = 1,
.max_media_buffer = 0,
.store = ctx->store,
.log = ctx->log,
.logf = ctx->logf,
.tn_size = ctx->tn_size,
.tn_qscale = ctx->tn_qscale,
.tesseract_lang = NULL,
.tesseract_path = NULL
};
return store_image_thumbnail(&media_ctx, img.thumb, img.tlength, doc, "x.jpeg");
} }
int store_thumbnail_rgb24(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, document_t *doc) { int store_thumbnail_rgb24(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, document_t *doc) {
@ -70,7 +84,7 @@ int store_thumbnail_rgb24(scan_raw_ctx_t *ctx, libraw_processed_image_t *img, do
avcodec_receive_packet(jpeg_encoder, &jpeg_packet); avcodec_receive_packet(jpeg_encoder, &jpeg_packet);
APPEND_LONG_META(doc, MetaThumbnail, 1) APPEND_LONG_META(doc, MetaThumbnail, 1)
ctx->store((char *) doc->path_md5, sizeof(doc->path_md5), (char *) jpeg_packet.data, jpeg_packet.size); ctx->store((char *) doc->doc_id, sizeof(doc->doc_id), (char *) jpeg_packet.data, jpeg_packet.size);
av_packet_unref(&jpeg_packet); av_packet_unref(&jpeg_packet);
av_free(*scaled_frame->data); av_free(*scaled_frame->data);
@ -171,6 +185,13 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
return; return;
} }
int tn_ok = 0;
if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) {
tn_ok = store_thumbnail_jpeg(ctx, libraw_lib->thumbnail, doc);
} else if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP) {
// TODO: technically this should work but is currently untested
int errc = 0; int errc = 0;
libraw_processed_image_t *thumb = libraw_dcraw_make_mem_thumb(libraw_lib, &errc); libraw_processed_image_t *thumb = libraw_dcraw_make_mem_thumb(libraw_lib, &errc);
if (errc != 0) { if (errc != 0) {
@ -180,16 +201,9 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
return; return;
} }
int tn_ok = 0;
if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_JPEG) {
tn_ok = store_thumbnail_jpeg(ctx, thumb, doc);
} else if (libraw_lib->thumbnail.tformat == LIBRAW_THUMBNAIL_BITMAP) {
// TODO: technically this should work but is currently untested
tn_ok = store_thumbnail_rgb24(ctx, thumb, doc); tn_ok = store_thumbnail_rgb24(ctx, thumb, doc);
} }
libraw_dcraw_clear_mem(thumb);
if (tn_ok == TRUE) { if (tn_ok == TRUE) {
free(buf); free(buf);
libraw_close(libraw_lib); libraw_close(libraw_lib);
@ -206,7 +220,7 @@ void parse_raw(scan_raw_ctx_t *ctx, vfile_t *f, document_t *doc) {
libraw_dcraw_process(libraw_lib); libraw_dcraw_process(libraw_lib);
errc = 0; int errc = 0;
libraw_processed_image_t *img = libraw_dcraw_make_mem_image(libraw_lib, &errc); libraw_processed_image_t *img = libraw_dcraw_make_mem_image(libraw_lib, &errc);
if (errc != 0) { if (errc != 0) {
free(buf); free(buf);

View File

@ -48,6 +48,10 @@ typedef int scan_code_t;
#define CTX_LOG_FATALF(filepath, fmt, ...) ctx->logf(filepath, LEVEL_FATAL, fmt, __VA_ARGS__); exit(-1); #define CTX_LOG_FATALF(filepath, fmt, ...) ctx->logf(filepath, LEVEL_FATAL, fmt, __VA_ARGS__); exit(-1);
#define CTX_LOG_FATAL(filepath, str) ctx->log(filepath, LEVEL_FATAL, str); exit(-1); #define CTX_LOG_FATAL(filepath, str) ctx->log(filepath, LEVEL_FATAL, str); exit(-1);
#define MD5_STR_LENGTH 33
#define SIST_DOC_ID_LEN MD5_STR_LENGTH
#define SIST_INDEX_ID_LEN MD5_STR_LENGTH
enum metakey { enum metakey {
// String // String
MetaContent = 1, MetaContent = 1,
@ -103,7 +107,7 @@ typedef struct meta_line {
typedef struct document { typedef struct document {
unsigned char path_md5[MD5_DIGEST_LENGTH]; char doc_id[SIST_DOC_ID_LEN];
unsigned long size; unsigned long size;
unsigned int mime; unsigned int mime;
int mtime; int mtime;
@ -159,7 +163,7 @@ typedef struct parse_job_t {
int base; int base;
int ext; int ext;
struct vfile vfile; struct vfile vfile;
unsigned char parent[MD5_DIGEST_LENGTH]; char parent[SIST_DOC_ID_LEN];
char filepath[1]; char filepath[1];
} parse_job_t; } parse_job_t;