感谢原作 @winffy2009 :jetbra-server-go 用golang 重复造个轮子吧
Update:
搞了个单 HTML 版,部署更方便了。
https://linux.do/t/topic/49380
原作者的服务只支持 IDE 本身的激活,想激活插件还有点麻烦。因此糊了一个自动拉取所有插件并展示到页面的能力,直接一个页面搞定所有插件。
每次进程重启的时候会自动拉取插件列表进行比对,有新的插件会自动加入。
// plugin.go,用于自动获取所有插件的 Code 信息,并写入 plugins.json 文件,方便下次启动直接加载
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"strconv"
"time"
)
const (
pluginBaseUrl = "https://plugins.jetbrains.com"
pluginJsonFile = "plugins.json"
)
var (
client = http.Client{
Timeout: 60 * time.Second,
}
allPluginList []*Plugin
)
type ListPluginResponse struct {
Plugins []*Plugin `json:"plugins,omitempty"`
Total int `json:"total,omitempty"`
CorrectedQuery string `json:"correctedQuery,omitempty"`
}
type Plugin struct {
Id int `json:"id"`
Code string `json:"code,omitempty"`
Name string `json:"name"`
PricingModel string `json:"pricingModel"`
Icon string `json:"icon"`
}
type PluginDetail struct {
Id int `json:"id"`
PurchaseInfo struct {
ProductCode string `json:"productCode"`
BuyUrl interface{} `json:"buyUrl"`
PurchaseTerms interface{} `json:"purchaseTerms"`
Optional bool `json:"optional"`
TrialPeriod int `json:"trialPeriod"`
} `json:"purchaseInfo"`
}
func init() {
pluginFile, err := os.OpenFile(pluginJsonFile, os.O_RDONLY, 0644)
if err == nil {
err = json.NewDecoder(pluginFile).Decode(&allPluginList)
if err != nil {
panic(err)
}
}
loadAllPlugin()
savePlugin()
return
}
func loadAllPlugin() {
pluginIdCodeMap := make(map[int]string, len(allPluginList))
for _, plugin := range allPluginList {
pluginIdCodeMap[plugin.Id] = plugin.Code
}
pluginList, err := client.Get(pluginBaseUrl + "/api/searchPlugins?max=10000&offset=0")
if err != nil {
panic(err)
return
}
defer pluginList.Body.Close()
var listPluginResponse ListPluginResponse
err = json.NewDecoder(pluginList.Body).Decode(&listPluginResponse)
if err != nil {
panic(err)
return
}
for i, plugin := range listPluginResponse.Plugins {
if plugin.PricingModel == "FREE" {
continue
}
if pluginIdCodeMap[plugin.Id] != "" {
continue
}
fmt.Println("found new plugin ", plugin.Name, plugin.PricingModel)
listPluginResponse.Plugins[i].Icon = pluginBaseUrl + listPluginResponse.Plugins[i].Icon
allPluginList = append(allPluginList, listPluginResponse.Plugins[i])
}
for _, plugin := range allPluginList {
if plugin.Code == "" {
plugin.Code = getCodeByPluginID(plugin.Id)
fmt.Println("new plugin code ", plugin.Name, plugin.Code)
}
}
}
func getCodeByPluginID(id int) string {
pluginDetailResp, err := client.Get(pluginBaseUrl + "/api/plugins/" + strconv.Itoa(id))
if err != nil {
panic(err)
}
defer pluginDetailResp.Body.Close()
var pluginDetail PluginDetail
err = json.NewDecoder(pluginDetailResp.Body).Decode(&pluginDetail)
if err != nil {
panic(err)
}
return pluginDetail.PurchaseInfo.ProductCode
}
func savePlugin() {
f, err := os.Create(pluginJsonFile)
if err != nil {
panic(err)
}
err = json.NewEncoder(f).Encode(allPluginList)
if err != nil {
panic(err)
}
}
main.go 里的修改,在渲染时将获取到的插件信息传入:
func index(c *gin.Context) {
c.HTML(http.StatusOK, "/index.html", gin.H{
"title": "请选择",
"licenseeName": "Evaluator",
"assigneeName": "Evaluator",
"expiryDate": "2099-12-31",
"plugins": allPluginList,
})
}
html 模板的修改,在最后一个 article 和 main 之间新增模板渲染:
</article>
{{- range .plugins}}
<article class="card" data-product="{{ .Name }}" data-product-codes="{{ .Code }}">
<header>
<div class="flex items-center justify-between px-6 pt-1 pb-0 bg-card radius-1">
<div class="avatar-wrapper flex items-center justify-center overflow-hidden shrink-0">
<div class="icon" role="img" style="background-image: url('{{ .Icon }}')"></div>
</div>
</div>
<hr/>
</header>
<div class="pd-6 overflow-hidden bg-card container radius-1">
<h1 class="truncate truncate-1 color-primary mt-0 overflow-ellipsis" title='{{ .Name }}'>{{ .Name }}</h1>
<p title="单据复制激活码到剪切板" class="truncate text-sm text-grey" onclick="copyLicense(this)"
data-content="复制到剪切板">
**********
</p>
</div>
<div class="mask"></div>
<div class="mask mask-c-1"></div>
</article>
{{- end }}
</main>
改造后效果:
当前已获取到的完整 plugins.json,放根目录可以避免重复获取。
plugins.json.zip (7.2 KB)