diff --git a/file_upload/README.md b/file_upload/README.md index c3906c4..3b1c540 100644 --- a/file_upload/README.md +++ b/file_upload/README.md @@ -2,14 +2,14 @@ - 配置openresty - ```nginx + ```nginx configuration # 配置文件路径 # /usr/local/openresty/nginx/conf/nginx.conf # http contex 中添加lua脚本的路径 lua_package_path "/usr/local/openresty/resty_funcs/?.lua;;"; ``` - ```nginx + ```nginx configuration # 子域名配置文件路径 # /usr/local/openresty/nginx/conf.d/music-room.conf diff --git a/file_upload/upload_image.lua b/file_upload/upload_image.lua index 3d42697..2576751 100644 --- a/file_upload/upload_image.lua +++ b/file_upload/upload_image.lua @@ -1,79 +1,110 @@ +-- Require lua modules local upload = require "upload" local uuid = require "uuid" +local redis = require "redis" +local cjson = require "cjson" +--------------------------------------------------------------------------------------- -local chunk_size = 5 -- should be set to 4096 or 8192 - -- for real-world settings - -local form, err = upload:new(chunk_size) - -local output_image_filename_uuid = uuid.generate(); - - -if not form then - ngx.log(ngx.ERR, "failed to new upload: ", err) - ngx.exit(500) -end - -form:set_timeout(1000) -- 1 sec - --- String split +-- Functions : String split string.split = function(s, p) local rt= {} string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end ) return rt end --- Get file trim +-- Functions : Get file trim string.trim = function(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end +--------------------------------------------------------------------------------------- --- Upload file save path config in nginx.conf -local saveRootPath = ngx.var.store_dir +-- Init +---- Upload init +local chunk_size = 5 -- should be set to 4096 or 8192 +-- for real-world settings -local fileToSave +local form, error = upload:new(chunk_size) + +if not form then + ngx.log(ngx.ERR, "Fail to create new form: ", error) + ngx.exit(500) +end + +---- Redis init +------ Connect to redis +local redis_task_database = redis:new() + +redis_task_database:set_timeouts(1000, 1000, 1000) + +local ok, error = redis_task_database:connect("127.0.0.1", 6379) +if not ok then + ngx.log(ngx.ERR, "Fail to connect redis: ", error) + ngx.exit(500) +end +--------------------------------------------------------------------------------------- + +-- Save upload images +---- Upload file save path config in nginx.conf +local save_upload_file_path = ngx.var.store_dir +local file_to_save local ret_save = false local upload_image_filename local save_image_filename - local upload_image_table = {} +local data_table = {} local upload_image_index = 1 +form:set_timeout(1000) -- 1 sec + +---- Read image file from http packet and save it while true do - local typ, res, err = form:read() - if not typ then - ngx.log(ngx.ERR, "failed to read: ", err) - return + + local http_type, result, error = form:read() + + if not http_type then + ngx.log(ngx.ERR, "Failed to read form: ", error) + ngx.exit(500) end - if typ == "header" then - -- 开始读取 http header - -- 解析出本次上传的文件名 - local key = res[1] - local value = res[2] + + if http_type == "header" then + -- Start to read http header + + local key = result[1] + local value = result[2] + if key == "Content-Disposition" then - -- 解析出本次上传的文件名 - -- form-data; name="testFileName"; filename="testfile.txt" - local kvlist = string.split(value, ';') - for _, kv in ipairs(kvlist) do - local seg = string.trim(kv) - if seg:find("filename") then - local kvfile = string.split(seg, "=") - upload_image_filename = string.sub(kvfile[2], 2, -2) - ngx.log(ngx.INFO,"Upload origin image is ", upload_image_filename) + -- Analyze this time upload image filename , use ; as interval + -- Like: form-data; name="testFileName"; filename="testfile.txt" + local key_value_list = string.split(value, ';') + for _, key_value in ipairs(key_value_list) do + + local segment = string.trim(key_value) + + if segment:find("filename") then + + local key_value_file = string.split(segment, "=") + upload_image_filename = string.sub(key_value_file[2], 2, -2) + + ngx.log(ngx.INFO, "Upload origin filename: ", upload_image_filename) + + -- Save upload file if upload_image_filename then -- Save file name with generate uuid - save_image_filename = uuid:generate() + save_image_filename = uuid:generate() -- Generate save filename uuid save_image_filename = save_image_filename .. '.' .. upload_image_filename:match(".+%.(%w+)$") - fileToSave = io.open(saveRootPath .. save_image_filename, "w+") - if not fileToSave then - ngx.log(ngx.ERR, " Error: Failed to open file ", save_image_filename) - return - else - ngx.log(ngx.INFO, "Open file ok ", save_image_filename) + file_to_save = io.open(save_upload_file_path .. save_image_filename, "w+") - upload_image_table[upload_image_index] = saveRootPath .. save_image_filename .. " " + if not file_to_save then + ngx.log(ngx.ERR , "Fail open file: ", save_image_filename) + ngx.exit(500) + else + ngx.log(ngx.INFO, "Success open file: ", save_image_filename) + + -- Save all upload files as a table + data_table[upload_image_index] = save_image_filename + upload_image_table[upload_image_index] = save_upload_file_path .. save_image_filename .. " " ngx.log(ngx.INFO, "Insert upload image table "..upload_image_index.." with "..upload_image_table[upload_image_index]) upload_image_index = upload_image_index + 1 @@ -83,58 +114,106 @@ while true do end end end - elseif typ == "body" then - -- 开始读取 http body - if fileToSave then - fileToSave:write(res) + + elseif http_type == "body" then + + -- Start to read http body + if file_to_save then + file_to_save:write(result) end - elseif typ == "part_end" then - -- 文件写结束,关闭文件 - if fileToSave then - fileToSave:close() - fileToSave = nil + + elseif http_type == "part_end" then + + -- Write to save file finish + if file_to_save then + file_to_save:close() + file_to_save = nil end ret_save = true - elseif typ == "eof" then - -- 文件读取结束 + + elseif http_type == "eof" then + -- Read file end break else - ngx.log(ngx.INFO, "do other things") + ngx.log(ngx.INFO, "Maybe do other things") end end -if ret_save then - ngx.log(ngx.INFO, "Show all upload files\n") +--------------------------------------------------------------------------------------- - -- Show all upload files +-- Show all input and may output files +if ret_save then + ngx.log(ngx.INFO, "Show all upload save files\n") + + ---- Show all upload save files upload_image_index = upload_image_index -1 for i = 1, upload_image_index do ngx.log(ngx.INFO, "Save upload file is : " .. upload_image_table[i]) end + --------------------------------------------------------------------------------------- - image_append_coroutine = coroutine.create( - function () - -- Append images - -- ngx.log(ngx.INFO,"Upload image number is : " , upload_image_index ) - local append_images_path - append_images_path = table.concat(upload_image_table) - ngx.log(ngx.INFO, "Input images list : " , append_images_path) + -- Communicate with front end + ---- Generate task uuid + local task_uuid = uuid.generate(); + --------------------------------------------------------------------------------------- --- local append_output_image = saveRootPath .. uuid.generate()..".jpg "; - local append_output_image = saveRootPath .. output_image_filename_uuid..".jpg "; - ngx.log(ngx.INFO, "Output image is : "..append_output_image) + -- Construct {key: task_id | value: [images] } in json + -- Example: + -- {"task_id":"488a8e6c556a-4271-adec--071e843c9856","data:"[\"2109aac0-556a-4271-adec-9eac494f622f.jpg\",\"488a8e6c-01e6-4cb3-af88-a1d90e04e6b8.jpg\",\"c3f76317-592f-4117-ab0d-071e843c9856.jpg\"]"} + local task_table = {} + task_table["task_id"] = task_uuid + task_table["data"] = data_table - -- Debug - ngx.log(ngx.INFO, '/usr/local/ImageMagick/bin/magick convert -append '..append_images_path..' '..append_output_image) + local task_jason = cjson.encode(task_table) + ngx.log(ngx.INFO , task_jason) -- Response to front end + --------------------------------------------------------------------------------------- - local call_imagemagick_cmd = io.popen('/usr/local/ImageMagick/bin/magick convert -append '..append_images_path..' '..append_output_image) - local imagemagick_cmd_replay = call_imagemagick_cmd:read("*all") - ngx.log(ngx.INFO, imagemagick_cmd_replay) + -- Redis control + ---- Set json to redis + ok, error = redis_task_database:set(task_uuid, task_jason) + if not ok then + ngx.log(ngx.ERR , "Failed to set task json: ", error) + ngx.exit(500) + end + ngx.log(ngx.INFO , "Set redis task json result: ", ok) + ---- Get data from redis + local result, error = redis_task_database:get(task_uuid) + if not result then + ngx.log(ngx.ERR , "Failed to get task json: ", error) + ngx.exit(500) + end - end + if result == ngx.null then + ngx.log(ngx.ERR , "Not found task id") + ngx.exit(500) + end + + ngx.log(ngx.INFO, "Get redis task id: " .. task_uuid .. " | value :" .. result) + --------------------------------------------------------------------------------------- + + -- Create task + local result = ngx.location.capture( + '/mock_task_server', + { + method = ngx.HTTP_POST, + body = ngx.encode_args({task = task_jason}) + } ) + ngx.say(result.body) + + -- Response task ID to front end + ngx.say(task_uuid) + + -- Mock a image append request from task from task server + local result = ngx.location.capture( + '/image_append', + { + method = ngx.HTTP_POST, + body = ngx.encode_args({task = task_jason}) + } + ) + ngx.say(result.body) - coroutine.resume(image_append_coroutine) end \ No newline at end of file