Moved config to its own directory
This commit is contained in:
parent
d329c36653
commit
5ddf50a152
87
app.go
87
app.go
|
@ -14,22 +14,34 @@ import (
|
||||||
rumblelivestreamlib "github.com/tylertravisty/rumble-livestream-lib-go"
|
rumblelivestreamlib "github.com/tylertravisty/rumble-livestream-lib-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
type chat struct {
|
||||||
configFilepath = "./config.json"
|
username string
|
||||||
)
|
password string
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
type App struct {
|
type App struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cfg *config.App
|
cfg *config.App
|
||||||
cfgMu sync.Mutex
|
cfgMu sync.Mutex
|
||||||
api *api.Api
|
api *api.Api
|
||||||
apiMu sync.Mutex
|
apiMu sync.Mutex
|
||||||
|
logError *log.Logger
|
||||||
|
logInfo *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp creates a new App application struct
|
// NewApp creates a new App application struct
|
||||||
func NewApp() *App {
|
func NewApp() *App {
|
||||||
return &App{api: api.NewApi()}
|
app := &App{}
|
||||||
|
err := app.initLog()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("error initializing log")
|
||||||
|
}
|
||||||
|
|
||||||
|
app.api = api.NewApi(app.logError, app.logInfo)
|
||||||
|
|
||||||
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
// startup is called when the app starts. The context is saved
|
// startup is called when the app starts. The context is saved
|
||||||
|
@ -37,15 +49,31 @@ func NewApp() *App {
|
||||||
func (a *App) startup(ctx context.Context) {
|
func (a *App) startup(ctx context.Context) {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
a.api.Startup(ctx)
|
a.api.Startup(ctx)
|
||||||
|
|
||||||
err := a.loadConfig()
|
err := a.loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: handle error better on startup
|
a.logError.Fatal("error loading config: ", err)
|
||||||
log.Fatal("error loading config: ", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) initLog() error {
|
||||||
|
fp, err := config.LogFile()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting filepath for log file")
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(fp, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error opening log file")
|
||||||
|
}
|
||||||
|
|
||||||
|
a.logInfo = log.New(f, "[info]", log.LstdFlags|log.Lshortfile)
|
||||||
|
a.logError = log.New(f, "[error]", log.LstdFlags|log.Lshortfile)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) loadConfig() error {
|
func (a *App) loadConfig() error {
|
||||||
cfg, err := config.Load(configFilepath)
|
cfg, err := config.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
return fmt.Errorf("error loading config: %v", err)
|
return fmt.Errorf("error loading config: %v", err)
|
||||||
|
@ -60,7 +88,7 @@ func (a *App) loadConfig() error {
|
||||||
|
|
||||||
func (a *App) newConfig() error {
|
func (a *App) newConfig() error {
|
||||||
cfg := &config.App{Channels: map[string]config.Channel{}}
|
cfg := &config.App{Channels: map[string]config.Channel{}}
|
||||||
err := cfg.Save(configFilepath)
|
err := cfg.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error saving new config: %v", err)
|
return fmt.Errorf("error saving new config: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -73,23 +101,12 @@ func (a *App) Config() *config.App {
|
||||||
return a.cfg
|
return a.cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) SaveConfig() error {
|
|
||||||
err := a.cfg.Save(configFilepath)
|
|
||||||
if err != nil {
|
|
||||||
// TODO: log error; return user error
|
|
||||||
return fmt.Errorf("Error saving config")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) AddChannel(url string) (*config.App, error) {
|
func (a *App) AddChannel(url string) (*config.App, error) {
|
||||||
client := rumblelivestreamlib.Client{StreamKey: url}
|
client := rumblelivestreamlib.Client{StreamKey: url}
|
||||||
resp, err := client.Request()
|
resp, err := client.Request()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log error
|
a.logError.Println("error executing api request:", err)
|
||||||
fmt.Println("error requesting api:", err)
|
return nil, fmt.Errorf("Error querying API. Verify key and try again.")
|
||||||
return nil, fmt.Errorf("error querying API")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name := resp.Username
|
name := resp.Username
|
||||||
|
@ -101,16 +118,14 @@ func (a *App) AddChannel(url string) (*config.App, error) {
|
||||||
defer a.cfgMu.Unlock()
|
defer a.cfgMu.Unlock()
|
||||||
_, err = a.cfg.NewChannel(url, name)
|
_, err = a.cfg.NewChannel(url, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log error
|
a.logError.Println("error creating new channel:", err)
|
||||||
fmt.Println("error creating new channel:", err)
|
return nil, fmt.Errorf("Error creating new channel. Try again.")
|
||||||
return nil, fmt.Errorf("error creating new channel")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.cfg.Save(configFilepath)
|
err = a.cfg.Save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log error
|
a.logError.Println("error saving config:", err)
|
||||||
fmt.Println("error saving config:", err)
|
return nil, fmt.Errorf("Error saving channel information. Try again.")
|
||||||
return nil, fmt.Errorf("error saving new channel")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.cfg, nil
|
return a.cfg, nil
|
||||||
|
@ -119,15 +134,13 @@ func (a *App) AddChannel(url string) (*config.App, error) {
|
||||||
func (a *App) StartApi(cid string) error {
|
func (a *App) StartApi(cid string) error {
|
||||||
channel, found := a.cfg.Channels[cid]
|
channel, found := a.cfg.Channels[cid]
|
||||||
if !found {
|
if !found {
|
||||||
// TODO: log error
|
a.logError.Println("could not find channel CID:", cid)
|
||||||
fmt.Println("could not find channel CID:", cid)
|
|
||||||
return fmt.Errorf("channel CID not found")
|
return fmt.Errorf("channel CID not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := a.api.Start(channel.ApiUrl, channel.Interval*time.Second)
|
err := a.api.Start(channel.ApiUrl, channel.Interval*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log error
|
a.logError.Println("error starting api:", err)
|
||||||
fmt.Println("error starting api:", err)
|
|
||||||
return fmt.Errorf("error starting API")
|
return fmt.Errorf("error starting API")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,34 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stream-chat-add-button {
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgba(6,23,38,1);
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-chat-add-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stream-chat-add-icon {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
.stream-chat-header {
|
.stream-chat-header {
|
||||||
text-align: left;
|
align-items: center;
|
||||||
background-color: rgba(6,23,38,1);
|
background-color: rgba(6,23,38,1);
|
||||||
border-bottom: 1px solid #495a6a;
|
border-bottom: 1px solid #495a6a;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
height: 19px;
|
height: 19px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stream-chat-title {
|
.stream-chat-title {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { PlusCircle } from '../assets/icons';
|
||||||
import './StreamChat.css';
|
import './StreamChat.css';
|
||||||
|
|
||||||
function StreamChat(props) {
|
function StreamChat(props) {
|
||||||
|
@ -5,6 +6,12 @@ function StreamChat(props) {
|
||||||
<div className='stream-chat'>
|
<div className='stream-chat'>
|
||||||
<div className='stream-chat-header'>
|
<div className='stream-chat-header'>
|
||||||
<span className='stream-chat-title'>{props.title}</span>
|
<span className='stream-chat-title'>{props.title}</span>
|
||||||
|
<button
|
||||||
|
onClick={() => console.log('Add chat bot')}
|
||||||
|
className='stream-chat-add-button'
|
||||||
|
>
|
||||||
|
<img className='stream-chat-add-icon' src={PlusCircle} />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
21
frontend/src/components/StreamChatMessage.css
Normal file
21
frontend/src/components/StreamChatMessage.css
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
.modal-chat {
|
||||||
|
align-items: center;
|
||||||
|
background-color: red;
|
||||||
|
color: black;
|
||||||
|
display: flex;
|
||||||
|
height: 50%;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 1;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
justify-content: center;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
13
frontend/src/components/StreamChatMessage.jsx
Normal file
13
frontend/src/components/StreamChatMessage.jsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import './StreamChatMessage.css';
|
||||||
|
|
||||||
|
export function StreamChatMessageModal() {
|
||||||
|
return (
|
||||||
|
<div className='modal-container'>
|
||||||
|
<div className='modal-chat'>
|
||||||
|
<span>hello world</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StreamChatMessageItem() {}
|
|
@ -11,6 +11,7 @@ import StreamActivity from '../components/StreamActivity';
|
||||||
import StreamChat from '../components/StreamChat';
|
import StreamChat from '../components/StreamChat';
|
||||||
import StreamInfo from '../components/StreamInfo';
|
import StreamInfo from '../components/StreamInfo';
|
||||||
import { NavSignIn } from './Navigation';
|
import { NavSignIn } from './Navigation';
|
||||||
|
import { StreamChatMessageItem, StreamChatMessageModal } from '../components/StreamChatMessage';
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -131,6 +132,7 @@ function Dashboard() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<StreamChatMessageModal />
|
||||||
<div className='modal' style={{ zIndex: modalZ ? 10 : -10 }}>
|
<div className='modal' style={{ zIndex: modalZ ? 10 : -10 }}>
|
||||||
<span>show this instead</span>
|
<span>show this instead</span>
|
||||||
<button onClick={closeModal}>close</button>
|
<button onClick={closeModal}>close</button>
|
||||||
|
|
|
@ -7,6 +7,19 @@
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.add-channel-description {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-channel-error {
|
||||||
|
color: red;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.signin-input-box {
|
.signin-input-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import ChannelList from '../components/ChannelList';
|
||||||
function SignIn() {
|
function SignIn() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [config, setConfig] = useState({ channels: {} });
|
const [config, setConfig] = useState({ channels: {} });
|
||||||
|
const [addChannelError, setAddChannelError] = useState('');
|
||||||
const [streamKey, setStreamKey] = useState('');
|
const [streamKey, setStreamKey] = useState('');
|
||||||
const updateStreamKey = (event) => setStreamKey(event.target.value);
|
const updateStreamKey = (event) => setStreamKey(event.target.value);
|
||||||
const [showStreamKey, setShowStreamKey] = useState(false);
|
const [showStreamKey, setShowStreamKey] = useState(false);
|
||||||
|
@ -34,6 +35,7 @@ function SignIn() {
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('error adding channel', err);
|
console.log('error adding channel', err);
|
||||||
|
setAddChannelError(err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,6 +54,9 @@ function SignIn() {
|
||||||
</div>
|
</div>
|
||||||
<div className='signin-input-box'>
|
<div className='signin-input-box'>
|
||||||
<label className='signin-label'>Add Channel</label>
|
<label className='signin-label'>Add Channel</label>
|
||||||
|
<span className='add-channel-description'>
|
||||||
|
Copy your API key from your Rumble account
|
||||||
|
</span>
|
||||||
<div className='signin-input-button'>
|
<div className='signin-input-button'>
|
||||||
<input
|
<input
|
||||||
id='StreamKey'
|
id='StreamKey'
|
||||||
|
@ -71,6 +76,9 @@ function SignIn() {
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<span className='add-channel-error'>
|
||||||
|
{addChannelError ? addChannelError : '\u00A0'}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='signin-footer'></div>
|
<div className='signin-footer'></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,7 @@ package api
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,12 +15,14 @@ type Api struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
cancelMu sync.Mutex
|
cancelMu sync.Mutex
|
||||||
|
logError *log.Logger
|
||||||
|
logInfo *log.Logger
|
||||||
querying bool
|
querying bool
|
||||||
queryingMu sync.Mutex
|
queryingMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApi() *Api {
|
func NewApi(logError *log.Logger, logInfo *log.Logger) *Api {
|
||||||
return &Api{}
|
return &Api{logError: logError, logInfo: logInfo}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) Startup(ctx context.Context) {
|
func (a *Api) Startup(ctx context.Context) {
|
||||||
|
@ -27,7 +30,7 @@ func (a *Api) Startup(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) Start(url string, interval time.Duration) error {
|
func (a *Api) Start(url string, interval time.Duration) error {
|
||||||
fmt.Println("Api.Start")
|
a.logInfo.Println("Api.Start")
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return fmt.Errorf("empty stream key")
|
return fmt.Errorf("empty stream key")
|
||||||
}
|
}
|
||||||
|
@ -38,21 +41,21 @@ func (a *Api) Start(url string, interval time.Duration) error {
|
||||||
a.queryingMu.Unlock()
|
a.queryingMu.Unlock()
|
||||||
|
|
||||||
if start {
|
if start {
|
||||||
fmt.Println("Starting querying")
|
a.logInfo.Println("Start querying")
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
a.cancelMu.Lock()
|
a.cancelMu.Lock()
|
||||||
a.cancel = cancel
|
a.cancel = cancel
|
||||||
a.cancelMu.Unlock()
|
a.cancelMu.Unlock()
|
||||||
go a.start(ctx, url, interval)
|
go a.start(ctx, url, interval)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Querying already started")
|
a.logInfo.Println("Querying already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) Stop() {
|
func (a *Api) Stop() {
|
||||||
fmt.Println("stop querying")
|
a.logInfo.Println("Stop querying")
|
||||||
a.cancelMu.Lock()
|
a.cancelMu.Lock()
|
||||||
if a.cancel != nil {
|
if a.cancel != nil {
|
||||||
a.cancel()
|
a.cancel()
|
||||||
|
@ -77,12 +80,12 @@ func (a *Api) start(ctx context.Context, url string, interval time.Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Api) query(url string) {
|
func (a *Api) query(url string) {
|
||||||
fmt.Println("QueryAPI")
|
a.logInfo.Println("QueryAPI")
|
||||||
client := rumblelivestreamlib.Client{StreamKey: url}
|
client := rumblelivestreamlib.Client{StreamKey: url}
|
||||||
resp, err := client.Request()
|
resp, err := client.Request()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log error
|
// TODO: log error
|
||||||
fmt.Println("client.Request err:", err)
|
a.logError.Println("api: error executing client request:", err)
|
||||||
a.Stop()
|
a.Stop()
|
||||||
runtime.EventsEmit(a.ctx, "QueryResponseError", "Failed to query API")
|
runtime.EventsEmit(a.ctx, "QueryResponseError", "Failed to query API")
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tylertravisty/go-utils/random"
|
"github.com/tylertravisty/go-utils/random"
|
||||||
|
@ -12,13 +14,69 @@ import (
|
||||||
const (
|
const (
|
||||||
CIDLen = 8
|
CIDLen = 8
|
||||||
DefaultInterval = 10
|
DefaultInterval = 10
|
||||||
|
|
||||||
|
configDir = ".rum-goggles"
|
||||||
|
configDirWin = "RumGoggles"
|
||||||
|
configFile = "config.json"
|
||||||
|
logFile = "logs.txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func LogFile() (string, error) {
|
||||||
|
dir, err := buildConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("config: error getting config directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(dir, logFile), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildConfigDir() (string, error) {
|
||||||
|
userDir, err := userDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error getting user directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dir string
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
dir = filepath.Join(userDir, configDirWin)
|
||||||
|
default:
|
||||||
|
dir = filepath.Join(userDir, configDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func userDir() (string, error) {
|
||||||
|
var dir string
|
||||||
|
var err error
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
dir, err = os.UserCacheDir()
|
||||||
|
default:
|
||||||
|
dir, err = os.UserHomeDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
return dir, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatMessage struct {
|
||||||
|
AsChannel bool `json:"as_channel"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
Interval time.Duration `json:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChatBot struct {
|
||||||
|
Messages []ChatMessage `json:"messages"`
|
||||||
|
// Commands []ChatCommand
|
||||||
|
}
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
ApiUrl string `json:"api_url"`
|
ApiUrl string `json:"api_url"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Interval time.Duration `json:"interval"`
|
Interval time.Duration `json:"interval"`
|
||||||
|
ChatBot ChatBot `json:"chat_bot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) NewChannel(url string, name string) (string, error) {
|
func (a *App) NewChannel(url string, name string) (string, error) {
|
||||||
|
@ -29,7 +87,7 @@ func (a *App) NewChannel(url string, name string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := a.Channels[id]; !exists {
|
if _, exists := a.Channels[id]; !exists {
|
||||||
a.Channels[id] = Channel{id, url, name, DefaultInterval}
|
a.Channels[id] = Channel{id, url, name, DefaultInterval, ChatBot{[]ChatMessage{}}}
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,31 +97,66 @@ type App struct {
|
||||||
Channels map[string]Channel `json:"channels"`
|
Channels map[string]Channel `json:"channels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(filepath string) (*App, error) {
|
func Load() (*App, error) {
|
||||||
|
dir, err := buildConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("config: error getting config directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := filepath.Join(dir, configFile)
|
||||||
|
app, err := load(fp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("config: error loading config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return app, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(filepath string) (*App, error) {
|
||||||
f, err := os.Open(filepath)
|
f, err := os.Open(filepath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("config: error opening file: %w", err)
|
return nil, fmt.Errorf("error opening file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var app App
|
var app App
|
||||||
decoder := json.NewDecoder(f)
|
decoder := json.NewDecoder(f)
|
||||||
err = decoder.Decode(&app)
|
err = decoder.Decode(&app)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("config: error decoding file into json: %v", err)
|
return nil, fmt.Errorf("error decoding file into json: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &app, nil
|
return &app, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *App) Save(filepath string) error {
|
func (a *App) Save() error {
|
||||||
b, err := json.MarshalIndent(app, "", "\t")
|
dir, err := buildConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("config: error encoding config into json: %v", err)
|
return fmt.Errorf("config: error getting config directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(filepath, b, 0666)
|
err = os.MkdirAll(dir, 0750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("config: error writing config file: %v", err)
|
return fmt.Errorf("config: error making config directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := filepath.Join(dir, configFile)
|
||||||
|
err = a.save(fp)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("config: error saving config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *App) save(filepath string) error {
|
||||||
|
b, err := json.MarshalIndent(app, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error encoding config into json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(filepath, b, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
Loading…
Reference in a new issue