blob: ad6afafa57e43848f273b2444c9943df7e2e548d [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"
14 "github.com/gin-gonic/gin"
Akronce286af2022-12-28 13:58:26 +010015 "github.com/joho/godotenv"
Akron65503a32023-01-02 12:38:32 +010016 "github.com/mattn/go-jsonpointer"
Akrone2161562022-12-19 17:05:39 +010017)
18
19var db *badger.DB
20
21func CheckSaleUrl(c *gin.Context) {
22
23 corpusID := c.Param("corpus_id")
24 docID := c.Param("doc_id")
25 textID := c.Param("text_id")
26
27 err := db.View(func(txn *badger.Txn) error {
28
29 item, err := txn.Get([]byte(corpusID + "/" + docID + "/" + textID))
30
31 if err != nil {
32 c.String(http.StatusNotFound, "No entry found")
Akron906a2c52022-12-21 11:35:28 +010033 return nil
Akrone2161562022-12-19 17:05:39 +010034 }
35
36 err = item.Value(func(v []byte) error {
37 c.String(http.StatusOK, string(v))
38 return nil
39 })
40
41 if err != nil {
Akronce5186d2022-12-21 11:15:50 +010042 return err
Akrone2161562022-12-19 17:05:39 +010043 }
44
45 return nil
46 })
47
48 if err != nil {
49 c.String(http.StatusNotFound, err.Error())
50 }
Akrone2161562022-12-19 17:05:39 +010051}
52
Akrona1f100a2023-03-07 11:03:01 +010053func add(dbx *badger.DB, corpusID, docID, textID string, provider string, url string) error {
54 err := dbx.Update(func(txn *badger.Txn) error {
Akron6aee7fe2022-12-20 16:00:54 +010055 err := txn.Set([]byte(corpusID+"/"+docID+"/"+textID), []byte(provider+","+url))
Akrone2161562022-12-19 17:05:39 +010056 return err
57 })
58 return err
59}
60
Akrona1f100a2023-03-07 11:03:01 +010061func InitDB(dir string) {
Akrone2161562022-12-19 17:05:39 +010062 if db != nil {
63 return
64 }
Akrona1f100a2023-03-07 11:03:01 +010065 db = initDB(dir)
66}
67
68func initDB(dir string) *badger.DB {
69 dbx, err := badger.Open(badger.DefaultOptions(dir))
Akrone2161562022-12-19 17:05:39 +010070 if err != nil {
71 log.Fatal(err)
72 }
Akrona1f100a2023-03-07 11:03:01 +010073 return dbx
Akrone2161562022-12-19 17:05:39 +010074}
75
76func closeDB() {
77 db.Close()
78}
79
Akrona1f100a2023-03-07 11:03:01 +010080func IndexDB(ri io.Reader) error {
81 return indexDB(ri, db)
82}
83
84// indexDB reads in a csv file and adds
85// information to the database
86func indexDB(ri io.Reader, dbx *badger.DB) error {
87
88 r := csv.NewReader(ri)
89
90 txn := dbx.NewTransaction(true)
91
92 i := 0
93
94 for {
95 record, err := r.Read()
96 if err == io.EOF {
97 break
98 }
99 if err != nil {
100 log.Fatal(err)
101 }
102
103 if err := txn.Set([]byte(record[0]), []byte(record[1]+","+record[2])); err == badger.ErrTxnTooBig {
104 log.Println("Commit", record[0], "after", i, "inserts")
105 i = 0
106 err = txn.Commit()
107 if err != nil {
108 log.Fatal("Unable to commit")
109 }
110 txn = db.NewTransaction(true)
111 _ = txn.Set([]byte(record[0]), []byte(record[1]+","+record[2]))
112 }
113 i++
114 }
115 return txn.Commit()
116}
117
Akrone2161562022-12-19 17:05:39 +0100118func setupRouter() *gin.Engine {
119 r := gin.Default()
Akron5e1252e2022-12-19 17:57:56 +0100120 r.LoadHTMLGlob("templates/*")
121
Akronce286af2022-12-28 13:58:26 +0100122 korapServer := os.Getenv("KORAP_SERVER")
123 if korapServer == "" {
124 korapServer = "https://korap.ids-mannheim.de"
125 }
126
Akron65503a32023-01-02 12:38:32 +0100127 var pluginManifest map[string]any
128 json.Unmarshal([]byte(`{
Akronde331792023-01-10 11:36:15 +0100129 "name" : "External Resources",
130 "desc" : "Retrieve content from an external provider",
Akron65503a32023-01-02 12:38:32 +0100131 "embed" : [{
132 "panel" : "match",
133 "title" : "Full Text",
134 "classes" : ["plugin", "cart"],
135 "icon" : "\f07a",
136 "onClick" : {
137 "action" : "addWidget",
138 "template":"",
139 "permissions": [
140 "scripts",
141 "popups"
142 ]
143 }
144 }]
145 }`), &pluginManifest)
146
Akronde331792023-01-10 11:36:15 +0100147 externalResources := os.Getenv("KORAP_EXTERNAL_RESOURCES")
148 if externalResources == "" {
149 externalResources = "https://korap.ids-mannheim.de/plugin/external/"
Akron65503a32023-01-02 12:38:32 +0100150 }
Akronde331792023-01-10 11:36:15 +0100151 jsonpointer.Set(pluginManifest, "/embed/0/onClick/template", externalResources)
Akron65503a32023-01-02 12:38:32 +0100152
Akron79d83482023-01-02 10:53:24 +0100153 r.Use(func() gin.HandlerFunc {
154 return func(c *gin.Context) {
155 h := c.Writer.Header()
156 h.Set("Access-Control-Allow-Origin", "null")
157 h.Set("Access-Control-Allow-Credentials", "null")
158 h.Set("Vary", "Origin")
159 }
160 }(),
161 )
162
Akron60e11602023-01-02 11:16:43 +0100163 // Return widget page
Akron6aee7fe2022-12-20 16:00:54 +0100164 r.GET("/", func(c *gin.Context) {
Akron5e1252e2022-12-19 17:57:56 +0100165 c.HTML(http.StatusOK, "main.html", gin.H{
Akronce286af2022-12-28 13:58:26 +0100166 "korapServer": korapServer,
Akron5e1252e2022-12-19 17:57:56 +0100167 })
168 })
169
Akronde331792023-01-10 11:36:15 +0100170 // Return resource information
Akronce5186d2022-12-21 11:15:50 +0100171 r.HEAD("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akrone2161562022-12-19 17:05:39 +0100172 r.GET("/:corpus_id/:doc_id/:text_id", CheckSaleUrl)
Akron60e11602023-01-02 11:16:43 +0100173
174 // Return plugin manifest
Akron65503a32023-01-02 12:38:32 +0100175 r.GET("/plugin.json", func(c *gin.Context) {
176 c.JSON(200, pluginManifest)
177 })
178
Akrone2161562022-12-19 17:05:39 +0100179 return r
180}
181
182func main() {
Akronbad28fe2023-03-17 11:14:56 +0100183 gin.SetMode(gin.ReleaseMode)
184
Akron3c58d0d2023-01-02 13:35:41 +0100185 if godotenv.Load() != nil {
186 log.Println(".env file not loaded.")
187 }
Akronce286af2022-12-28 13:58:26 +0100188
Akrona1f100a2023-03-07 11:03:01 +0100189 InitDB("db")
Akron3890fcc2022-12-20 15:26:36 +0100190 defer closeDB()
191
192 // Index csv file
193 if len(os.Args) > 1 {
194
195 file, err := os.Open(os.Args[1])
196 if err != nil {
197 log.Fatal(err)
198 }
Akron3890fcc2022-12-20 15:26:36 +0100199
Akrona1f100a2023-03-07 11:03:01 +0100200 fileExt := filepath.Ext(os.Args[1])
Akron3890fcc2022-12-20 15:26:36 +0100201
Akrona1f100a2023-03-07 11:03:01 +0100202 if fileExt == ".gz" || fileExt == ".csvz" {
203 var gzipr io.Reader
204 gzipr, err = gzip.NewReader(file)
Akron3890fcc2022-12-20 15:26:36 +0100205 if err != nil {
Akrona1f100a2023-03-07 11:03:01 +0100206 log.Fatal("Unable to open gzip file")
207 } else {
208 err = IndexDB(gzipr)
Akron3890fcc2022-12-20 15:26:36 +0100209 }
Akrona1f100a2023-03-07 11:03:01 +0100210 } else {
211 err = IndexDB(file)
Akron3890fcc2022-12-20 15:26:36 +0100212 }
Akron3890fcc2022-12-20 15:26:36 +0100213
214 if err != nil {
215 log.Fatal("Unable to commit")
216 }
Akron3890fcc2022-12-20 15:26:36 +0100217 }
Akrone2161562022-12-19 17:05:39 +0100218 r := setupRouter()
Akronce286af2022-12-28 13:58:26 +0100219
Akronde331792023-01-10 11:36:15 +0100220 port := os.Getenv("KORAP_EXTERNAL_RESOURCES_PORT")
Akronce286af2022-12-28 13:58:26 +0100221 if port == "" {
222 port = "5722"
223 }
224
225 log.Fatal(http.ListenAndServe(":"+port, r))
Akrone2161562022-12-19 17:05:39 +0100226}