blob: d0d9769f82a183ea38175f226afb225ed5563f47 [file] [log] [blame]
Akrone2161562022-12-19 17:05:39 +01001package main
2
3import (
Akrona1f100a2023-03-07 11:03:01 +01004 "compress/gzip"
Akron3890fcc2022-12-20 15:26:36 +01005 "encoding/csv"
Akron65503a32023-01-02 12:38:32 +01006 "encoding/json"
Akron3890fcc2022-12-20 15:26:36 +01007 "io"
Akrone2161562022-12-19 17:05:39 +01008 "log"
9 "net/http"
Akron3890fcc2022-12-20 15:26:36 +010010 "os"
Akrona1f100a2023-03-07 11:03:01 +010011 "path/filepath"
Akrone2161562022-12-19 17:05:39 +010012
13 badger "github.com/dgraph-io/badger/v3"
Akron83b77a72023-03-17 13:37:06 +010014 ginI18n "github.com/gin-contrib/i18n"
Akrone2161562022-12-19 17:05:39 +010015 "github.com/gin-gonic/gin"
Akronce286af2022-12-28 13:58:26 +010016 "github.com/joho/godotenv"
Akron65503a32023-01-02 12:38:32 +010017 "github.com/mattn/go-jsonpointer"
Akron83b77a72023-03-17 13:37:06 +010018 "golang.org/x/text/language"
Akrone2161562022-12-19 17:05:39 +010019)
20
21var db *badger.DB
22
23func CheckSaleUrl(c *gin.Context) {
24
25 corpusID := c.Param("corpus_id")
26 docID := c.Param("doc_id")
27 textID := c.Param("text_id")
28
29 err := db.View(func(txn *badger.Txn) error {
30
31 item, err := txn.Get([]byte(corpusID + "/" + docID + "/" + textID))
32
33 if err != nil {
34 c.String(http.StatusNotFound, "No entry found")
Akron906a2c52022-12-21 11:35:28 +010035 return nil
Akrone2161562022-12-19 17:05:39 +010036 }
37
38 err = item.Value(func(v []byte) error {
39 c.String(http.StatusOK, string(v))
40 return nil
41 })
42
43 if err != nil {
Akronce5186d2022-12-21 11:15:50 +010044 return err
Akrone2161562022-12-19 17:05:39 +010045 }
46
47 return nil
48 })
49
50 if err != nil {
51 c.String(http.StatusNotFound, err.Error())
52 }
Akrone2161562022-12-19 17:05:39 +010053}
54
Akrona1f100a2023-03-07 11:03:01 +010055func add(dbx *badger.DB, corpusID, docID, textID string, provider string, url string) error {
56 err := dbx.Update(func(txn *badger.Txn) error {
Akron6aee7fe2022-12-20 16:00:54 +010057 err := txn.Set([]byte(corpusID+"/"+docID+"/"+textID), []byte(provider+","+url))
Akrone2161562022-12-19 17:05:39 +010058 return err
59 })
60 return err
61}
62
Akrona1f100a2023-03-07 11:03:01 +010063func InitDB(dir string) {
Akrone2161562022-12-19 17:05:39 +010064 if db != nil {
65 return
66 }
Akrona1f100a2023-03-07 11:03:01 +010067 db = initDB(dir)
68}
69
70func initDB(dir string) *badger.DB {
71 dbx, err := badger.Open(badger.DefaultOptions(dir))
Akrone2161562022-12-19 17:05:39 +010072 if err != nil {
73 log.Fatal(err)
74 }
Akrona1f100a2023-03-07 11:03:01 +010075 return dbx
Akrone2161562022-12-19 17:05:39 +010076}
77
78func closeDB() {
79 db.Close()
80}
81
Akrona1f100a2023-03-07 11:03:01 +010082func IndexDB(ri io.Reader) error {
83 return indexDB(ri, db)
84}
85
86// indexDB reads in a csv file and adds
87// information to the database
88func indexDB(ri io.Reader, dbx *badger.DB) error {
89
90 r := csv.NewReader(ri)
91
92 txn := dbx.NewTransaction(true)
93
94 i := 0
95
96 for {
97 record, err := r.Read()
98 if err == io.EOF {
99 break
100 }
101 if err != nil {
Akronf4d6add2024-11-14 15:36:14 +0100102 log.Println(err)
103 continue;
Akrona1f100a2023-03-07 11:03:01 +0100104 }
105
106 if err := txn.Set([]byte(record[0]), []byte(record[1]+","+record[2])); err == badger.ErrTxnTooBig {
107 log.Println("Commit", record[0], "after", i, "inserts")
108 i = 0
109 err = txn.Commit()
110 if err != nil {
111 log.Fatal("Unable to commit")
112 }
113 txn = db.NewTransaction(true)
114 _ = txn.Set([]byte(record[0]), []byte(record[1]+","+record[2]))
115 }
116 i++
117 }
118 return txn.Commit()
119}
120
Akrone2161562022-12-19 17:05:39 +0100121func setupRouter() *gin.Engine {
Akron83b77a72023-03-17 13:37:06 +0100122 gin.SetMode(gin.ReleaseMode)
123
Akrone2161562022-12-19 17:05:39 +0100124 r := gin.Default()
Akron83b77a72023-03-17 13:37:06 +0100125
126 // apply i18n middleware
127 r.Use(ginI18n.Localize(ginI18n.WithBundle(&ginI18n.BundleCfg{
128 RootPath: "./i18n",
129 AcceptLanguage: []language.Tag{language.German, language.English},
130 DefaultLanguage: language.English,
131 UnmarshalFunc: json.Unmarshal,
132 FormatBundleFile: "json",
133 })))
134
Akron5e1252e2022-12-19 17:57:56 +0100135 r.LoadHTMLGlob("templates/*")
136
Akronce286af2022-12-28 13:58:26 +0100137 korapServer := os.Getenv("KORAP_SERVER")
138 if korapServer == "" {
139 korapServer = "https://korap.ids-mannheim.de"
140 }
141
Akron65503a32023-01-02 12:38:32 +0100142 var pluginManifest map[string]any
143 json.Unmarshal([]byte(`{
Akronde331792023-01-10 11:36:15 +0100144 "name" : "External Resources",
145 "desc" : "Retrieve content from an external provider",
Akron65503a32023-01-02 12:38:32 +0100146 "embed" : [{
147 "panel" : "match",
148 "title" : "Full Text",
149 "classes" : ["plugin", "cart"],
150 "icon" : "\f07a",
151 "onClick" : {
152 "action" : "addWidget",
153 "template":"",
154 "permissions": [
155 "scripts",
156 "popups"
157 ]
158 }
159 }]
160 }`), &pluginManifest)
161
Akronde331792023-01-10 11:36:15 +0100162 externalResources := os.Getenv("KORAP_EXTERNAL_RESOURCES")
163 if externalResources == "" {
164 externalResources = "https://korap.ids-mannheim.de/plugin/external/"
Akron65503a32023-01-02 12:38:32 +0100165 }
Akronde331792023-01-10 11:36:15 +0100166 jsonpointer.Set(pluginManifest, "/embed/0/onClick/template", externalResources)
Akron65503a32023-01-02 12:38:32 +0100167
Akron79d83482023-01-02 10:53:24 +0100168 r.Use(func() gin.HandlerFunc {
169 return func(c *gin.Context) {
170 h := c.Writer.Header()
171 h.Set("Access-Control-Allow-Origin", "null")
172 h.Set("Access-Control-Allow-Credentials", "null")
173 h.Set("Vary", "Origin")
174 }
175 }(),
176 )
177
Akron60e11602023-01-02 11:16:43 +0100178 // Return widget page
Akron6aee7fe2022-12-20 16:00:54 +0100179 r.GET("/", func(c *gin.Context) {
Akron5e1252e2022-12-19 17:57:56 +0100180 c.HTML(http.StatusOK, "main.html", gin.H{
Akron83b77a72023-03-17 13:37:06 +0100181 "korapServer": korapServer,
Akronf9caa3b2023-08-22 16:01:59 +0200182 "title": ginI18n.MustGetMessage(c, "fulltext"),
183 "noAccess": ginI18n.MustGetMessage(c, "noAccess"),
184 "fromProvider": ginI18n.MustGetMessage(c, "fromProvider"),
Akron5e1252e2022-12-19 17:57:56 +0100185 })
186 })
187
Akronde331792023-01-10 11:36:15 +0100188 // Return resource information
Akronce5186d2022-12-21 11:15:50 +0100189 r.HEAD("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akrone2161562022-12-19 17:05:39 +0100190 r.GET("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akron60e11602023-01-02 11:16:43 +0100191
192 // Return plugin manifest
Akron65503a32023-01-02 12:38:32 +0100193 r.GET("/plugin.json", func(c *gin.Context) {
194 c.JSON(200, pluginManifest)
195 })
196
Akrone2161562022-12-19 17:05:39 +0100197 return r
198}
199
200func main() {
Akron3c58d0d2023-01-02 13:35:41 +0100201 if godotenv.Load() != nil {
202 log.Println(".env file not loaded.")
203 }
Akronce286af2022-12-28 13:58:26 +0100204
Akrona1f100a2023-03-07 11:03:01 +0100205 InitDB("db")
Akron3890fcc2022-12-20 15:26:36 +0100206 defer closeDB()
207
208 // Index csv file
209 if len(os.Args) > 1 {
210
211 file, err := os.Open(os.Args[1])
212 if err != nil {
213 log.Fatal(err)
214 }
Akron3890fcc2022-12-20 15:26:36 +0100215
Akrona1f100a2023-03-07 11:03:01 +0100216 fileExt := filepath.Ext(os.Args[1])
Akron3890fcc2022-12-20 15:26:36 +0100217
Akrona1f100a2023-03-07 11:03:01 +0100218 if fileExt == ".gz" || fileExt == ".csvz" {
219 var gzipr io.Reader
220 gzipr, err = gzip.NewReader(file)
Akron3890fcc2022-12-20 15:26:36 +0100221 if err != nil {
Akrona1f100a2023-03-07 11:03:01 +0100222 log.Fatal("Unable to open gzip file")
223 } else {
224 err = IndexDB(gzipr)
Akron3890fcc2022-12-20 15:26:36 +0100225 }
Akrona1f100a2023-03-07 11:03:01 +0100226 } else {
227 err = IndexDB(file)
Akron3890fcc2022-12-20 15:26:36 +0100228 }
Akron3890fcc2022-12-20 15:26:36 +0100229
230 if err != nil {
231 log.Fatal("Unable to commit")
232 }
Akrona99d90d2024-03-19 11:56:28 +0100233 log.Println("indexation successfull")
234 return
Akron3890fcc2022-12-20 15:26:36 +0100235 }
Akron83b77a72023-03-17 13:37:06 +0100236
Akrone2161562022-12-19 17:05:39 +0100237 r := setupRouter()
Akronce286af2022-12-28 13:58:26 +0100238
Akronde331792023-01-10 11:36:15 +0100239 port := os.Getenv("KORAP_EXTERNAL_RESOURCES_PORT")
Akronce286af2022-12-28 13:58:26 +0100240 if port == "" {
241 port = "5722"
242 }
243
Akron80a3d272023-03-20 15:24:37 +0100244 log.Println("Starting server on port " + port)
245
Akronce286af2022-12-28 13:58:26 +0100246 log.Fatal(http.ListenAndServe(":"+port, r))
Akrone2161562022-12-19 17:05:39 +0100247}