From 93f354370aaa633841e54ed014fad0cc6f4d74fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=E8=8F=8C?= Date: Thu, 28 Apr 2022 20:40:16 +0800 Subject: [PATCH] update file --- .gitignore | 1 + Dockerfile | 2 +- configs/config.yml | 12 ++--- .../{index.b2aedd95.js => index.a180db26.js} | 2 +- dist/index.html | 2 +- docker-compose.yml | 42 +++++++++++++++ pkg/db/db.go | 13 +++-- pkg/log/log.go | 10 ++-- route/route.go | 4 +- route/tinyurl/tinyurl.go | 23 +++----- tests/dl.go | 24 --------- tests/dump.go | 54 ------------------- tests/lru.go | 18 ------- 13 files changed, 75 insertions(+), 132 deletions(-) rename dist/assets/{index.b2aedd95.js => index.a180db26.js} (99%) create mode 100644 docker-compose.yml delete mode 100644 tests/dl.go delete mode 100644 tests/dump.go delete mode 100644 tests/lru.go diff --git a/.gitignore b/.gitignore index f0f6403..3a0d5c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ bin/tinyurl +test/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 78347e2..93de14b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM golang:alpine as builder +LABEL anther="github.com/Sakurasan" # RUN apt install -y git make RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk update && apk --no-cache add make git -LABEL anther="cjun" WORKDIR /tinyurl COPY . /tinyurl ENV GO111MODULE=on diff --git a/configs/config.yml b/configs/config.yml index 12a551d..05e0ecb 100644 --- a/configs/config.yml +++ b/configs/config.yml @@ -5,7 +5,7 @@ server: data: database: driver: mysql - source: root:root@tcp(127.0.0.1:3306)/test + source: tinyurl:tinyurl@tcp(127.0.0.1:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local redis: addr: 127.0.0.1:6379 read_timeout: 0.2s @@ -16,8 +16,8 @@ log: development: true rotate: filename: ./app.log - maxsize: 10 - maxage: 7 - maxbackups: - localtime: - compress: + maxsize: 10 #Mb + maxage: 7 #day + # maxbackups: + # localtime: + # compress: diff --git a/dist/assets/index.b2aedd95.js b/dist/assets/index.a180db26.js similarity index 99% rename from dist/assets/index.b2aedd95.js rename to dist/assets/index.a180db26.js index 23f70a2..e521878 100644 --- a/dist/assets/index.b2aedd95.js +++ b/dist/assets/index.a180db26.js @@ -303,4 +303,4 @@ PERFORMANCE OF THIS SOFTWARE. * https://clipboardjs.com/ * * Licensed MIT © Zeno Rocha - */(function(e,t){(function(r,o){e.exports=o()})(vh,function(){return function(){var n={686:function(s,a,i){i.d(a,{default:function(){return ot}});var l=i(279),c=i.n(l),u=i(370),d=i.n(u),g=i(817),v=i.n(g);function A(I){try{return document.execCommand(I)}catch{return!1}}var $=function(L){var P=v()(L);return A("cut"),P},C=$;function E(I){var L=document.documentElement.getAttribute("dir")==="rtl",P=document.createElement("textarea");P.style.fontSize="12pt",P.style.border="0",P.style.padding="0",P.style.margin="0",P.style.position="absolute",P.style[L?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return P.style.top="".concat(D,"px"),P.setAttribute("readonly",""),P.value=I,P}var K=function(L){var P=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";if(typeof L=="string"){var N=E(L);P.container.appendChild(N),D=v()(N),A("copy"),N.remove()}else D=v()(L),A("copy");return D},q=K;function V(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?V=function(P){return typeof P}:V=function(P){return P&&typeof Symbol=="function"&&P.constructor===Symbol&&P!==Symbol.prototype?"symbol":typeof P},V(I)}var pe=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},P=L.action,D=P===void 0?"copy":P,N=L.container,Q=L.target,ce=L.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Q!==void 0)if(Q&&V(Q)==="object"&&Q.nodeType===1){if(D==="copy"&&Q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(Q.hasAttribute("readonly")||Q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ce)return q(ce,{container:N});if(Q)return D==="cut"?C(Q):q(Q,{container:N})},Ee=pe;function W(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?W=function(P){return typeof P}:W=function(P){return P&&typeof Symbol=="function"&&P.constructor===Symbol&&P!==Symbol.prototype?"symbol":typeof P},W(I)}function ae(I,L){if(!(I instanceof L))throw new TypeError("Cannot call a class as a function")}function re(I,L){for(var P=0;P0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=W(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var Q=this;this.listener=d()(N,"click",function(ce){return Q.onClick(ce)})}},{key:"onClick",value:function(N){var Q=N.delegateTarget||N.currentTarget,ce=this.action(Q)||"copy",Ke=Ee({action:ce,container:this.container,target:this.target(Q),text:this.text(Q)});this.emit(Ke?"success":"error",{action:ce,text:Ke,trigger:Q,clearSelection:function(){Q&&Q.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return te("action",N)}},{key:"defaultTarget",value:function(N){var Q=te("target",N);if(Q)return document.querySelector(Q)}},{key:"defaultText",value:function(N){return te("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var Q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return q(N,Q)}},{key:"cut",value:function(N){return C(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Q=typeof N=="string"?[N]:N,ce=!!document.queryCommandSupported;return Q.forEach(function(Ke){ce=ce&&!!document.queryCommandSupported(Ke)}),ce}}]),P}(c()),ot=Re},828:function(s){var a=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function l(c,u){for(;c&&c.nodeType!==a;){if(typeof c.matches=="function"&&c.matches(u))return c;c=c.parentNode}}s.exports=l},438:function(s,a,i){var l=i(828);function c(g,v,A,$,C){var E=d.apply(this,arguments);return g.addEventListener(A,E,C),{destroy:function(){g.removeEventListener(A,E,C)}}}function u(g,v,A,$,C){return typeof g.addEventListener=="function"?c.apply(null,arguments):typeof A=="function"?c.bind(null,document).apply(null,arguments):(typeof g=="string"&&(g=document.querySelectorAll(g)),Array.prototype.map.call(g,function(E){return c(E,v,A,$,C)}))}function d(g,v,A,$){return function(C){C.delegateTarget=l(C.target,v),C.delegateTarget&&$.call(g,C)}}s.exports=u},879:function(s,a){a.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},a.nodeList=function(i){var l=Object.prototype.toString.call(i);return i!==void 0&&(l==="[object NodeList]"||l==="[object HTMLCollection]")&&"length"in i&&(i.length===0||a.node(i[0]))},a.string=function(i){return typeof i=="string"||i instanceof String},a.fn=function(i){var l=Object.prototype.toString.call(i);return l==="[object Function]"}},370:function(s,a,i){var l=i(879),c=i(438);function u(A,$,C){if(!A&&!$&&!C)throw new Error("Missing required arguments");if(!l.string($))throw new TypeError("Second argument must be a String");if(!l.fn(C))throw new TypeError("Third argument must be a Function");if(l.node(A))return d(A,$,C);if(l.nodeList(A))return g(A,$,C);if(l.string(A))return v(A,$,C);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function d(A,$,C){return A.addEventListener($,C),{destroy:function(){A.removeEventListener($,C)}}}function g(A,$,C){return Array.prototype.forEach.call(A,function(E){E.addEventListener($,C)}),{destroy:function(){Array.prototype.forEach.call(A,function(E){E.removeEventListener($,C)})}}}function v(A,$,C){return c(document.body,A,$,C)}s.exports=u},817:function(s){function a(i){var l;if(i.nodeName==="SELECT")i.focus(),l=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var c=i.hasAttribute("readonly");c||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),c||i.removeAttribute("readonly"),l=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var u=window.getSelection(),d=document.createRange();d.selectNodeContents(i),u.removeAllRanges(),u.addRange(d),l=u.toString()}return l}s.exports=a},279:function(s){function a(){}a.prototype={on:function(i,l,c){var u=this.e||(this.e={});return(u[i]||(u[i]=[])).push({fn:l,ctx:c}),this},once:function(i,l,c){var u=this;function d(){u.off(i,d),l.apply(c,arguments)}return d._=l,this.on(i,d,c)},emit:function(i){var l=[].slice.call(arguments,1),c=((this.e||(this.e={}))[i]||[]).slice(),u=0,d=c.length;for(u;u{const t=(e==null?void 0:e.appendToBody)===void 0?!0:e.appendToBody;return{toClipboard(n,r){return new Promise((o,s)=>{const a=document.createElement("button"),i=new c0(a,{text:()=>n,action:()=>"copy",container:r!==void 0?r:document.body});i.on("success",l=>{i.destroy(),o(l)}),i.on("error",l=>{i.destroy(),s(l)}),t&&document.body.appendChild(a),a.click(),t&&document.body.removeChild(a)})}}};const d0=j("div",{class:"header"},null,-1),h0={class:"middle"},p0=j("img",{src:kh,alt:"",class:"tinylogo"},null,-1),g0={key:0,class:"tinyout"},v0={class:"outstyle"},m0=["href"],b0={style:{display:"block"}},y0=j("div",{class:"padding"},null,-1),_0=j("div",{class:"footer"},[j("div",null,"Copyright \xA9 2022 \u{1F42E}\u{1F37A} All Rights Reserved.")],-1),w0={setup(e){const{toClipboard:t}=f0(),n=Ce(""),r=Ce(""),o=Ce(!1);let s=()=>{Up({method:"post",url:"/api/v1/tiny",data:{longUrl:n.value}}).then(i=>{console.log(i.data),r.value=i.data.shortUrl,o.value=!0})};const a=async i=>{Mh({title:"Success",message:"This is a success message",type:"success"});try{await t(i),console.log("Copied to clipboard")}catch(l){console.error(l)}};return(i,l)=>{const c=Kd,u=gh;return k(),H(we,null,[d0,j("div",h0,[p0,ge(c,{modelValue:n.value,"onUpdate:modelValue":l[0]||(l[0]=d=>n.value=d),onKeyup:Wc(y(s),["enter"]),class:"tinyinput",style:{"border-radius":"15px"},placeholder:"\u{1F37A} "},null,8,["modelValue","onKeyup"])]),o.value?(k(),H("div",g0,[j("div",v0,[j("a",{href:r.value,style:{"font-size":"25px",color:"black","background-color":"lightsalmon","text-decoration":"none"},target:"_blank"},Kt(r.value),9,m0),ge(u,{icon:y(Rf),onClick:l[1]||(l[1]=d=>a(r.value)),style:{border:"none","margin-left":"10px"},size:"large",circle:""},null,8,["icon"])]),j("div",b0,[ge(y(vn),{url:r.value,twitter:!0,google:!0},null,8,["url"])])])):J("",!0),y0,_0],64)}}};Jc(w0).mount("#app"); + */(function(e,t){(function(r,o){e.exports=o()})(vh,function(){return function(){var n={686:function(s,a,i){i.d(a,{default:function(){return ot}});var l=i(279),c=i.n(l),u=i(370),d=i.n(u),g=i(817),v=i.n(g);function A(I){try{return document.execCommand(I)}catch{return!1}}var $=function(L){var P=v()(L);return A("cut"),P},C=$;function E(I){var L=document.documentElement.getAttribute("dir")==="rtl",P=document.createElement("textarea");P.style.fontSize="12pt",P.style.border="0",P.style.padding="0",P.style.margin="0",P.style.position="absolute",P.style[L?"right":"left"]="-9999px";var D=window.pageYOffset||document.documentElement.scrollTop;return P.style.top="".concat(D,"px"),P.setAttribute("readonly",""),P.value=I,P}var K=function(L){var P=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},D="";if(typeof L=="string"){var N=E(L);P.container.appendChild(N),D=v()(N),A("copy"),N.remove()}else D=v()(L),A("copy");return D},q=K;function V(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?V=function(P){return typeof P}:V=function(P){return P&&typeof Symbol=="function"&&P.constructor===Symbol&&P!==Symbol.prototype?"symbol":typeof P},V(I)}var pe=function(){var L=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},P=L.action,D=P===void 0?"copy":P,N=L.container,Q=L.target,ce=L.text;if(D!=="copy"&&D!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Q!==void 0)if(Q&&V(Q)==="object"&&Q.nodeType===1){if(D==="copy"&&Q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(D==="cut"&&(Q.hasAttribute("readonly")||Q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ce)return q(ce,{container:N});if(Q)return D==="cut"?C(Q):q(Q,{container:N})},Ee=pe;function W(I){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?W=function(P){return typeof P}:W=function(P){return P&&typeof Symbol=="function"&&P.constructor===Symbol&&P!==Symbol.prototype?"symbol":typeof P},W(I)}function ae(I,L){if(!(I instanceof L))throw new TypeError("Cannot call a class as a function")}function re(I,L){for(var P=0;P0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=W(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var Q=this;this.listener=d()(N,"click",function(ce){return Q.onClick(ce)})}},{key:"onClick",value:function(N){var Q=N.delegateTarget||N.currentTarget,ce=this.action(Q)||"copy",Ke=Ee({action:ce,container:this.container,target:this.target(Q),text:this.text(Q)});this.emit(Ke?"success":"error",{action:ce,text:Ke,trigger:Q,clearSelection:function(){Q&&Q.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return te("action",N)}},{key:"defaultTarget",value:function(N){var Q=te("target",N);if(Q)return document.querySelector(Q)}},{key:"defaultText",value:function(N){return te("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var Q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return q(N,Q)}},{key:"cut",value:function(N){return C(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Q=typeof N=="string"?[N]:N,ce=!!document.queryCommandSupported;return Q.forEach(function(Ke){ce=ce&&!!document.queryCommandSupported(Ke)}),ce}}]),P}(c()),ot=Re},828:function(s){var a=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function l(c,u){for(;c&&c.nodeType!==a;){if(typeof c.matches=="function"&&c.matches(u))return c;c=c.parentNode}}s.exports=l},438:function(s,a,i){var l=i(828);function c(g,v,A,$,C){var E=d.apply(this,arguments);return g.addEventListener(A,E,C),{destroy:function(){g.removeEventListener(A,E,C)}}}function u(g,v,A,$,C){return typeof g.addEventListener=="function"?c.apply(null,arguments):typeof A=="function"?c.bind(null,document).apply(null,arguments):(typeof g=="string"&&(g=document.querySelectorAll(g)),Array.prototype.map.call(g,function(E){return c(E,v,A,$,C)}))}function d(g,v,A,$){return function(C){C.delegateTarget=l(C.target,v),C.delegateTarget&&$.call(g,C)}}s.exports=u},879:function(s,a){a.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},a.nodeList=function(i){var l=Object.prototype.toString.call(i);return i!==void 0&&(l==="[object NodeList]"||l==="[object HTMLCollection]")&&"length"in i&&(i.length===0||a.node(i[0]))},a.string=function(i){return typeof i=="string"||i instanceof String},a.fn=function(i){var l=Object.prototype.toString.call(i);return l==="[object Function]"}},370:function(s,a,i){var l=i(879),c=i(438);function u(A,$,C){if(!A&&!$&&!C)throw new Error("Missing required arguments");if(!l.string($))throw new TypeError("Second argument must be a String");if(!l.fn(C))throw new TypeError("Third argument must be a Function");if(l.node(A))return d(A,$,C);if(l.nodeList(A))return g(A,$,C);if(l.string(A))return v(A,$,C);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function d(A,$,C){return A.addEventListener($,C),{destroy:function(){A.removeEventListener($,C)}}}function g(A,$,C){return Array.prototype.forEach.call(A,function(E){E.addEventListener($,C)}),{destroy:function(){Array.prototype.forEach.call(A,function(E){E.removeEventListener($,C)})}}}function v(A,$,C){return c(document.body,A,$,C)}s.exports=u},817:function(s){function a(i){var l;if(i.nodeName==="SELECT")i.focus(),l=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var c=i.hasAttribute("readonly");c||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),c||i.removeAttribute("readonly"),l=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var u=window.getSelection(),d=document.createRange();d.selectNodeContents(i),u.removeAllRanges(),u.addRange(d),l=u.toString()}return l}s.exports=a},279:function(s){function a(){}a.prototype={on:function(i,l,c){var u=this.e||(this.e={});return(u[i]||(u[i]=[])).push({fn:l,ctx:c}),this},once:function(i,l,c){var u=this;function d(){u.off(i,d),l.apply(c,arguments)}return d._=l,this.on(i,d,c)},emit:function(i){var l=[].slice.call(arguments,1),c=((this.e||(this.e={}))[i]||[]).slice(),u=0,d=c.length;for(u;u{const t=(e==null?void 0:e.appendToBody)===void 0?!0:e.appendToBody;return{toClipboard(n,r){return new Promise((o,s)=>{const a=document.createElement("button"),i=new c0(a,{text:()=>n,action:()=>"copy",container:r!==void 0?r:document.body});i.on("success",l=>{i.destroy(),o(l)}),i.on("error",l=>{i.destroy(),s(l)}),t&&document.body.appendChild(a),a.click(),t&&document.body.removeChild(a)})}}};const d0=j("div",{class:"header"},null,-1),h0={class:"middle"},p0=j("img",{src:kh,alt:"",class:"tinylogo"},null,-1),g0={key:0,class:"tinyout"},v0={class:"outstyle"},m0=["href"],b0={style:{display:"block"}},y0=j("div",{class:"padding"},null,-1),_0=j("div",{class:"footer"},[j("div",null,"Copyright \xA9 2022 \u{1F42E}\u{1F37A} All Rights Reserved.")],-1),w0={setup(e){const{toClipboard:t}=f0(),n=Ce(""),r=Ce(""),o=Ce(!1);let s=()=>{Up({method:"post",url:"/api/v1/tiny",data:{longUrl:n.value}}).then(i=>{r.value=i.data.shortUrl,o.value=!0})};const a=async i=>{Mh({title:"Success",message:"This is a success message",type:"success"});try{await t(i),console.log("Copied to clipboard")}catch(l){console.error(l)}};return(i,l)=>{const c=Kd,u=gh;return k(),H(we,null,[d0,j("div",h0,[p0,ge(c,{modelValue:n.value,"onUpdate:modelValue":l[0]||(l[0]=d=>n.value=d),onKeyup:Wc(y(s),["enter"]),class:"tinyinput",style:{"border-radius":"15px"},placeholder:"\u{1F37A} "},null,8,["modelValue","onKeyup"])]),o.value?(k(),H("div",g0,[j("div",v0,[j("a",{href:r.value,style:{"font-size":"25px",color:"black","background-color":"lightsalmon","text-decoration":"none"},target:"_blank"},Kt(r.value),9,m0),ge(u,{icon:y(Rf),onClick:l[1]||(l[1]=d=>a(r.value)),style:{border:"none","margin-left":"10px"},size:"large",circle:""},null,8,["icon"])]),j("div",b0,[ge(y(vn),{url:r.value,twitter:!0,google:!0},null,8,["url"])])])):J("",!0),y0,_0],64)}}};Jc(w0).mount("#app"); diff --git a/dist/index.html b/dist/index.html index 2a2c2a9..e069dc5 100644 --- a/dist/index.html +++ b/dist/index.html @@ -5,7 +5,7 @@ TinyUrl - + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..46acf3f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +version: '3' +services: + tinyurl: + # The official v2 Traefik docker image + image: mirrors2/tinyurl + container_name: tinyurl + restart: always + ports: + - "2830:2830" + # volumes: #default log term + # - $PWD/log:/app/tinyurl/log + # - config.yml:/app/tinyurl/configs/config.yml + entrypoint: + - DSN=tinyurl:tinyurl@tcp(db:3306)/tinyurl?charset=utf8mb4 + logging: + driver: "json-file" + options: + max-size: "10m" + + tinyurl_db: + image: mariadb + container_name: tinyurl_db + restart: always + networks: + - gitea + expose: + - 3306 + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + environment: + - MYSQL_ROOT_PASSWORD=supermen + - MYSQL_DATABASE=tinyurl + - MYSQL_USER=tinyurl + - MYSQL_PASSWORD=tinyurl + - TZ=Asia/Shanghai + volumes: + - ./db:/var/lib/mysql + # 标准 Linux 系统下使用 + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + # healthcheck: + # test: ["CMD-SHELL", "/etc/init.d/mysql status"] + # interval: 30s \ No newline at end of file diff --git a/pkg/db/db.go b/pkg/db/db.go index b9af8ee..d6c6fa2 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -1,6 +1,7 @@ package db import ( + "os" "time" "gorm.io/driver/mysql" @@ -13,10 +14,11 @@ var ( type TinyUrl struct { gorm.Model - LongUrl string `gorm:"size:200"` - ShortUrl string `gorm:"size:50"` + LongUrl string `gorm:"size:7713"` + ShortUrl string `gorm:"size:20"` ExpireTime time.Time Counter float64 + AddIP string } type URLDetail struct { @@ -27,7 +29,12 @@ type URLDetail struct { func InitDb() { // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情 - dsn := "tinyurl:tinyurl@tcp(42.192.36.14:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local" + var dsn string + if len(os.Getenv("DSN")) > 1 { + dsn = os.Getenv("DSN") + } else { + dsn = "tinyurl:tinyurl@tcp(42.192.36.14:3306)/tinyurl?charset=utf8mb4&parseTime=True&loc=Local" + } var err error DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { diff --git a/pkg/log/log.go b/pkg/log/log.go index eb750be..935f62f 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -85,11 +85,11 @@ func getConsoleEncoder() zapcore.Encoder { func getFileWriter(c config.Rotate) zapcore.WriteSyncer { logger := &lumberjack.Logger{ Filename: c.Filename, - MaxSize: c.MaxSize, - MaxAge: c.MaxAge, - MaxBackups: c.MaxBackups, - LocalTime: c.LocalTime, - Compress: c.Compress, + MaxSize: c.MaxSize, //Mb + MaxAge: c.MaxAge, //days + MaxBackups: c.MaxBackups, //int backup maximum number of old log files + LocalTime: c.LocalTime, //bool backup files is the computer's local time + Compress: c.Compress, //bool } return zapcore.AddSync(logger) } diff --git a/route/route.go b/route/route.go index 325df50..b76ca72 100644 --- a/route/route.go +++ b/route/route.go @@ -11,8 +11,8 @@ import ( func Route(f *flamego.Flame) { f.Get("/version", auth.Basic("admin", "admin"), func() string { return "1.1.1" }) // f.Get("/{url: **, capture: 10}", tinyurl.TinyurlHandler) - f.Get("/{url: **, capture: 10}", tinyurl.TinyUtlTo) - f.Router.Any("/api/v1/tiny", binding.JSON(tinyurl.Param{}), tinyurl.TinyUrl) + f.Get("/{url: **, capture: 10}", tinyurl.TinyUrlTo) + f.Post("/api/v1/tiny", binding.JSON(tinyurl.Param{}), tinyurl.TinyUrl) } diff --git a/route/tinyurl/tinyurl.go b/route/tinyurl/tinyurl.go index 9aa4e6e..ce2b652 100644 --- a/route/tinyurl/tinyurl.go +++ b/route/tinyurl/tinyurl.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" "time" "tinyurl/pkg/base62" "tinyurl/pkg/config" @@ -53,18 +54,15 @@ func TinyUrl(c flamego.Context, w http.ResponseWriter, form Param, errs binding. _, _ = c.ResponseWriter().Write([]byte(fmt.Sprintf("Oops! Error occurred: %v", err))) return } + if !strings.HasPrefix(form.LongUrl, "http://") || !strings.HasPrefix(form.LongUrl, "https://") { + form.LongUrl = "http://" + form.LongUrl + } logger.Info(c.Request().Context(), form.LongUrl) var tm = data.TinyUrl{} tm.LongUrl = form.LongUrl - tm.ShortUrl = base62.TinyUrl(form.LongUrl + time.Now().String()) + tm.ShortUrl = base62.TinyUrl(form.LongUrl + "?" + time.Now().String()) if err := db.Create(&tm).Error; err != nil { logger.Info(c.Request().Context(), err.Error()) - // bytejson, _ := json.Marshal(map[string]interface{}{ - // "code": http.StatusBadGateway, - // "msg": "please try again", - // }) - // io.WriteString(c.ResponseWriter(), string(bytejson)) - // return w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]interface{}{ "code": http.StatusBadGateway, @@ -78,19 +76,10 @@ func TinyUrl(c flamego.Context, w http.ResponseWriter, form Param, errs binding. "msg": "success", "shortUrl": cfg.Server.Domain + tm.ShortUrl, }) - // bytejson, err := json.Marshal(map[string]interface{}{ - // "code": http.StatusOK, - // "msg": "success", - // "shortUrl": tm.ShortUrl, - // }) - // if err != nil { - // logger.Error(c.Request().Context(), err.Error()) - // } - // io.WriteString(c.ResponseWriter(), string(bytejson)) } -func TinyUtlTo(c flamego.Context, logger *log.Logger, db *gorm.DB, l *lru.Cache, cfg *config.Config) { +func TinyUrlTo(c flamego.Context, logger *log.Logger, db *gorm.DB, l *lru.Cache, cfg *config.Config) { tiny := c.Param("url") if v, ok := l.Get(tiny); ok { c.Redirect(v.(string), http.StatusFound) diff --git a/tests/dl.go b/tests/dl.go deleted file mode 100644 index 6645d5e..0000000 --- a/tests/dl.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "net/http" -) - -func main() { - dlpath := "http://pan.oneisall.xyz/Outline.apk" - req, _ := http.NewRequest(http.MethodHead, dlpath, nil) - rsp, _ := http.DefaultClient.Do(req) - defer rsp.Body.Close() - fmt.Println(rsp.Status) - // dump, _ := httputil.DumpResponse(rsp, false) - // fmt.Println(string(dump)) - // if rsp.Header != nil { - // fmt.Printf("%v", rsp.Header) - for k, v := range rsp.Header { - fmt.Println(k, v) - } - fmt.Println(rsp.Header.Get("Content-Length")) - fmt.Println(rsp.Header.Get("Accept-Ranges")) - -} diff --git a/tests/dump.go b/tests/dump.go deleted file mode 100644 index 369e316..0000000 --- a/tests/dump.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "net/http/httputil" -) - -func main() { - mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - bytereq, _ := httputil.DumpRequest(r, true) - bytebody, _ := io.ReadAll(r.Body) - log.Println(string(bytereq)) - m := map[string]interface{}{ - "host": r.Host, - "requestUrl": r.RequestURI, - "proto": r.Proto, - "path": r.URL.String(), - "method": r.Method, - "body": string(bytebody), - "header": r.Header, - "form": r.Form, - "postform": r.PostForm, - "dumpreq": string(bytereq), - } - bj, _ := json.Marshal(m) - fmt.Println(string(bj)) - // json.NewEncoder(w).Encode(m) - - for k, v := range cors { - w.Header().Set(k, v) - } - w.WriteHeader(http.StatusOK) - io.WriteString(w, string(bj)) - return - }) - server := http.Server{ - Addr: ":890", - Handler: mux, - } - server.ListenAndServe() -} - -var cors = map[string]string{ - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "POST,OPTIONS,GET", - "Access-Control-Max-Age": "3600", - "Access-Control-Allow-Headers": "accept,x-requested-with,Content-Type", - "Access-Control-Allow-Credentials": "true", -} diff --git a/tests/lru.go b/tests/lru.go deleted file mode 100644 index 798e16a..0000000 --- a/tests/lru.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "fmt" - - lru "github.com/hashicorp/golang-lru" -) - -func main() { - l, _ := lru.New(10) - for i := 0; i < 100; i++ { - l.Add(i, i) - } - for l.Len() > 0 { - fmt.Println(l.RemoveOldest()) - } - -}