5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 04:42:00 +08:00

Major updates

Automatic type conversion
Support struct data
Custom error handler
This commit is contained in:
Lea Anthony 2020-08-31 20:00:39 +10:00
parent 0ab6a93e0c
commit 43a5f410d9
6 changed files with 139 additions and 20 deletions

View File

@ -15,8 +15,7 @@ type Counter struct {
// WailsInit is called when the component is being initialised
func (c *Counter) WailsInit(runtime *wails.Runtime) error {
c.r = runtime
c.store = runtime.Store.New("Counter")
c.store.Set(0)
c.store = runtime.Store.New("Counter", 0)
return nil
}

View File

@ -5,5 +5,5 @@ package renderer
import "github.com/leaanthony/mewn"
func init() {
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94587f6f1b3712fd2a2be24e25639a95723df4b22a1ba4ae8bfae0d845945cffd00905b53b9298ac481d495911647ef7c3ec6fd9f2fd008278450ec9e1bc37336f77b0dc992c686ba861c707e592208f71d20c26401d3bea250d3337670ec2ce99049f057cdd5a17fc0497588943f2a853c78b7430e6f5647a8c71522f32b8285345416db3965bde3d03e356147230eac622888d341c4426030791cbce551eb8634710161fd9e3e3fde2336441e4b0d4067e73760b2e1c4ab32398dd069c5a14900e467c05217591450ec2c9fed5c9ce54ab733290e1b005bb4ca687cdc216c361f557043b0d4e9bd547b51a0e5f3af1b92d3f3ea8620729796ff35d012432fed262f2c71fe06bb366d96054b91b4eae5f82321e86e1901a09d430c6ff360c0d4266a297f43b9c25b63c8ac8e64e6638c47fa23ba95b84583a593b97395001a8d91505c3ed4038ea5e72dd7192c352ed8a409e46bcba85898cbf2e1df2655cba201bb6b48e96344ab4490c039153c72d6faf1bd8b125519847b1d0262ffde296b1865f0e6364e473363fb9eddbd6a2db55d4bec7f4cc64cb60f42b70a2080f8c073cce3e81a436ac43b4753658bca4582b7fbf374db0aa2cc005b8c75612c28182f072c4229d9d701c90971e128c5916c8043108acc6e91827352655c4c8cfb0d8ad087f7e8722b636376669cf99f8cee477e50c2274c66ad9595d3b67dd399bbcb3f94505559cb3d94756178efa12b65a6339b9df82f9f4e1f6dcaa433cb1fa4563963c375bd49beb66735d2dd39cdcc1fedc8abb7a8592b37957fab206823adc08656a38a2b750d9979b9f53e05b7528accad310272785542fe95e9bdceec55ee9c22f9cce57f0f6f990d8c3c2dbec0b04e10159cdd2da08be06704615429b07fb05339c2b51805985f58fa33665821c4dc20fcdc4245c5c30350b736a58a47f9fdedf892adbf4f2401d63b1bddbae226c46496157841f0b788022357c03deab15a421f68c0bbcd18e92bce297e94df97a4a97b4eacf2ceb997dc3a6fe645e4f4245a2fed4be9e5a56dc312ce23db7fce1a42dad1a6c9a2cdd15c540c270583f3c3e529023c60dec93df9cdd680fb4c5c7715b81aa27b93d6a692ec825b9d85216f76b5d007d98e97955f27e1cb18a171ec247bd01bb0bb4471f4bcb2ca0e44a1545126c422ecc054982de409ed85d10c907f8d70e7c486e7e4e1372a119a63c9be001f218aa0d7f55262f2055dc01968dd47207de160f90ba3809ee802021e7083f62e1d36675a73648c45c05953e01196b8a663153215b6320336bbc2d4094814656f4715d9f54ad1525153305b9288b536b77c09d6aab35253f39bbf7e0449ba97df8162fdb56f96a58dcca9ae3993b6c83ed57648cb69188da276dc25f5ebf734e1de8b8adf2270bc50ac2076572bbf907f618e4e26c343f57c4df8c46df8fdfbc79fdd7efbeff6ef4e6cdf8d57b15d6c2956b298b65f26fda629e185a726bf0ace10ea849b4f141990c5b57602cac9ddd27e8f0c7c3165a3a18634382a8252ac90ae57da27ca2926643c2220d6bedb9611c90ad97638ebfc5555d5c4efa5823bb84da6e8b43d5f90ce397e38144ca8fa494142ee598c5c8af4fd2e4be4993eb99994bfceff17136affb073abd296f3ac119b1ddf935753d2ca7258328810730d8d7cdcbbc9bcd852f7406b58bcaad761b30c1b36a988e198b55267f3971f00a8f409237790cfbe497e6ea04edc985617c30ea285d590ec6b173f4ae0208cd813b8991c4f41df4eb6d8d548dd0ef3894689f204edae8a055a13de4a4e94bb37943b91217bf5bf8cce9059c0063ab9819162bf43cf4445a60479081f77d10d718492fae373a6065d4854ffdc164a90fd641badbe62a409e62fe41b36735784ed7506013876796597fee9c7bf35f4ee9ef0ad2702b96d65dab6c4dfb3378526491f1301c36f7a4a881d6da77207c6ed38d7e6e34a4f25eafcce3637fb7ae758db175354ce9b7b00a49d9cecdc27cd22c73281281fd4f1a0bb8632890f1e504f00526b6a28ed54c2db3b0a36bacc38839082697c7c86bd977637438a71dbe4676127bd9fff1f8786c91e9b62c2976238f77b0ffa9aae8e973786773915993a9408df0db020923082b1fab7ce2204f7746ca8746228c5b89e0e468e27e68262ec7137721c7d529d57b5b992a57d432d64bc23a4f48e384e5a44917953ca842e7c967f5a03029b621d13998a0971a9c208c4d6066e7d88167762e8fb12c71333b8f95280b626bb794d5a7eaff78aafeff4ed573f9a497a03eeabdcb36cc6acb5549930efe49db0b0d07ec81adf4ef04c0492a06699021ab33b35ddd8e1c22659137c5fd39da132373c86c0e9f3edc5cd9cdd61a3008bc836da132a0dffed35f7cbbe284b06e6836ba7ca32e97f3e3eb88537ffed3108380b534c8b23a6f95f3a81bebd2d91448496e4c154ab44ab6ca7bc851bc34c2364ddaf807510b424e44f2bed68609612d35d9a42aab05854a6c55084255eb9d0ca2d955e7dcca87866e8d0093a4094af24d7baae3e49b1273072bed03e483c18034279d2a1add3f15854f01ca354acd8a1389c5780e050448d00b1eaa1dde5a51e92e5a0fb014474a014683c05ec722bfb3412f0fe9333d807db3ab685076d8bae3315e255e3954d7b67ee6e138faa1b1d560e632844ef7a10b3de8727a0a1b3a967830019133a57b2229cb7e826d3a9165e38cb6551454b3e1109afae1f898c55214408cfc5d9e4fcb947a72c3ea52b9cdcaf4a8bf085c1780bf28a9b290b00988005f8334bcb55cd8fc8005164c7eb5d6458eec08c3e1b4ec543706e37d359d9ea97a2f9e150e0520073011df85e0f4621780122cfd84133cffdbcc7bc27810a5ed740d10def67f88ccfb8fa59f6938f1edc999687367f3ea9b4a37b906953f3eb63f57106ae7fc4f878faad4e494a0114111ca4e4ea86ead43fa15437df3dbd52dd2da803b89806ad544e4b7f2786b57a9e3b5804e2daf7a7a7abc374f50baafbf25dc9bf7bb22e86d01e93d4789914ef9afa05c58803a45b67ba9452d39f9823ce8d5ad32896e4c00f7a08af2fb02562f872f41ed68cf7c5a092016f9bbec8bb1fb02f215a44fde860778484f2de7ad4a56dda26467f0d924ebc6ed5e55309c7c83150e37a218a369296734ff23bde929caaf956261f1f3c91b38bf6ddbb43565a29f7e4d045ebe159ea8a85bbb1275477af5ead5abe44aed56eb907c32ebb29ee455d949708e9c8a80fed2ae6ca2927dc9ead3875bb4082f5bdc6a03c99d452b78d9eaca16bb8da9eddccb766508d0c6b2c8a78d4c2cacca5104c7399bfc3b0000ffff0ba869f119160000")
mewn.AddAsset(".", "../../runtime/assets/wails.js", "1f8b08000000000000ff94587f6f1b3712fd2a2be24e25637a2be57ae8655536485d17f5c1b18b28b9fea1130a6a77243159917b24654590f9dd0fb3bfd7968b3b208857e4901cce7b33f37647ebbd4ebd329a6a767a9036f2e21466cd6004d4b2935a53bfb04b66c1efad8ef03986af85b1decd70891138244e2ab13c4f46535e4f26a71066f5228d8b5299e7d4346bb9e1dd33306ee25c8c26dd58807827348738159e439c89ce55eeb96527880d3eb2c7c7fbd567487d9cc15a69f8cd9a02ac3f966627d0fb1d58b9ca21194df8067c62030b1c622bfa57277b5dadcec848f86301661dcd8fbb95c9c7e3ea6feccddc5ba5371fe5663c7ee9c4e7b6fcf420f33d24e4bdc9f63990c0f84b8bc91f7f80abcd9a65a349e5ae1f5cbf04653af6e331d502a8668cff63ec1b84f44cade977384b4c791411cd9df4788cffe2eea46e11626945ed5c6a417aa07a9fe70cb783d852fb92eb96930cd6729f7bf234e2d52d7460fc75e9902be3d20559b3b5b1b4a451a474a419c419b5dcf0f6ba9e9d5a12f96588574a67a55fdc30d6f0cb628cb478cee627b77ddb5a74bbc6b5ef213933d93218fdf29c48c23de31e8f334f20a90deb1015d67883978cb7d2dd1f7413ac2a0b7001ee5108423850889d98b04017038e03f2d24184314b3d9921069ed5389dc2acc6a48a18f91956fb0de1cfef9087d6e646afcd3913d799fc2ead4684ce58ad3bab6b6b8d3d67937536bf482ff3733687c0eac2515fc2546b0c27f705e84f1f6ecfad3a8681d52f0ab3e4b9d9aade5c359bab6a99e2e40e0ee7565cd52ba4582cbbd2973610d4e1462813cd11bd954cbfdcfc9c002fe43137324b7c980d0aa95ad383d29939c407a972b7b22adbc0dbe743f10156cea45fc0c70e90d52ca98de0ab07ab651e2bfd60be60867319e7a0377efbe3a44d192f2633ff433331f317174c2efc926a16e83fe7f77771956d6a7da496b1d0de6d5f1136a524371bc24f393c409e68be03e7e406121f7ac639de684f4956f14bf7a65c3da54a5af567d6f5cca161537f32ab27a122517fea504fad2bee6816f09e057f18b4a54d834d93a5fb3c1f09188feb87c7470a62c2b88643f49b353be580b6f8586e2a50d52c332725f405b924170565e1b05539d087855a5625efc709ab78e1c07f543b307b4f7bf431b4cc024aae649e47de44e4425f90c8ab1d6491d9fb38fa00ffd983f3d1cdcf49442e14c39467333c409c7cb5e1af52673924925bc0b291186ec199fc01121b66de1e1124e41ce1272c7c4a6feee40e8998492f932720634d512ca4d2a75b0c646ab43339c465a091157d5cb783aab5a1a462664c2ecae2d4da1d71a7da6a4bc94fd61c1cd8b8cdd43e7cab976dab7cd52c14a2e6786a8f8537fd8a8cd1d60251fba4b4ffdbeb77d6ca239db6557eb030de80ff20756676ffc21e835c5c4c96e78af89bc9e4fbe99b37affffeddf7df4ddebc99be7a2ffd36b6e55aca4299fcbbb698479a96dc1a3d6bb823aa23a59d973ac5d6e519f35b6b0e113afcf158404b07ad8d8f10b54846692e9d8ba48b64d46c4858a07eab1cd78c03b2f572caf1777c551797411f6b64572c8b223f569d4f337e391d09a4fc440841e1524c5908fc7a9026f74d9a5c2ff452e07f8f8f8b65dd3fd0e95d79d319cec4c5de6da9ed61392f1944093c80c6beae5fe6dd6219bb5ca550bb28ed66bf03ed1dab86e994b15065f2ddc0c12f780492bcc9633844bf345727684f2e34e3a34947e9ca72340d9da3571540680edc0a8c24a6efa85f6f6ba46a847ec7a148b90871525a792573e520234d5f5a2c1bca95b8b8fdcaa556ad60008ca962a659a8d073d013699e9d4078def721bec648baf87aa73c564695bbc41d759a386f2c24fb22931eb2d5716d8df6a0b30433f149a481a1505e1b7b2dd32ded7ba32960902b57aabdcec9210a6c66d1d5b2589c73ef5eff997348cfc6b7c1f1a2f4b490d695dd0a84fe734719f7e37113378a9a6aab5c07eae7367de9e746934ae7d4463f3ef677eb5ae1145b61c3bc7e4bac9821dab9855fce9a65164527b0ff49b301b70c0537beec00be10855624b29af9655677f40f757ceba08953e0b58cbcd1ca9fd3225f031b8022fa3f1e1f4f2d64dd9625656fc4e90e0e3f551d22798efb6219a746a7d2531dbb224702c684958f557e7210c39d31857c2339a6ade4b06232b33f341397d399bd10d3ea94ea3db04cbd2fd430d64bea3aef48e384e1a4493f193dc85c65d167f92031c90a1fa90cb4576b0536268ccd606196d8d11766294ea12c990bb30c95c8f371610acaea53d59f9eaafebf53d5523ce94da8b77aefc60db3daf257d2a4837fd6f656cd017b6afb2ad1098a418e7aa191219b33b35d1f081c02658137cde239da332d32484d069f3edc5c995d61346804de4291cb14e8b7ff7617df6e3821ac1b5a4c2edfc8cbf5f2f43ae0d45fff32c620606df6c3ccae4b71537005b9d15528d12a2aa47390a1186a847212b5f1f7712d303989a3f7b5d68c086ba9c9665599ce2954e2ad4210aade61858f9b5d55c68d7868e8d6083a419aa044dfb4a75a4ebe2931b7b051ce43361a8d4873d25021a9fea928a47290b6517e261e4836c633c8c143845e705fedf0d6c4958ea3f5004b70a41474d4c7d83b59e077c6abf53179a62fb00f77150dca8e5d7750c6abc42b87eadad6cf3c1c473f14b62ecc5c86d0a93e74be075d4687b0a1639103ed11395dba1747653f88b0ed47a26cc4c1b40a852a361e43533f2c9fb2508a0c0881bfcbb27999524f6e585d2a3369991ef51786eb1cf017255516123683d8c3572f346f2d57263b6281059d5d6d559e213bfc783c2f5bd88dc6785fcde767aade8b67f9630ec8014cc477de5bb5da7ba0044b3fe104cfff36758e30eee3d276be05f06ffb3fe2d4b98fa59f891ff8f6e44cb4b93359f58da69bdc82cc1e1fdb9f1bf0b573eea7e347596a7c4ad088a0a8658313aa5b2b9f7cc550dffc76758bb4d660071190ad3a09fc569c6ecd26b1bc16e489e155b34f4ef7fa094af7f5b7897bfd7e9f7b55e490dc73942cc99cff0ad2fa15c821b2dd4b326ad3d91df2a057b7ca24bad11eec83cccbef1558bd2cbe54b5a33df37925a858e0efd22fda1c72c836903c79bb1ee1213df59db5aa5b768ba2bdc6671d6d1bb77b554173f20d5638dc88628ce6a5ce51fc8fe4a6a750bf568a8585cf83377a7edbb669a3cb441f7e9d045ebe650ee4d5add9c475477af5ead5abe84aee375b1f7dd2dbb29e6455d989708e0c45407f6957365119bf64f5e9c32d5af8972d6e9586e8cea015bc6c7565f2fd4ed776f665bb3204686358e0f3463fe6466628aac392cdfe1b0000ffff40209e8869160000")
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -20,36 +20,53 @@ export function New(name, optionalDefault) {
var data;
// Check we are initialised
if( !window.wails) {
throw Error('Wails is not initialised');
}
// Store for the callbacks
let callbacks = [];
// Subscribe to updates by providing a callback
this.subscribe = (callback) => {
callbacks.push(callback);
};
// sets the store data to the provided `newdata` value
this.set = (newdata) => {
data = newdata;
// Emit the data
window.wails.Events.Emit('wails:sync:store:updated:'+name, data);
// Emit a notification to back end
window.wails.Events.Emit('wails:sync:store:updatedbyfrontend:'+name, JSON.stringify(data));
// Notify callbacks
callbacks.forEach( function(callback) {
callback(data);
});
};
// update mutates the value in the store by calling the
// provided method with the current value. The value returned
// by the updater function will be set as the new store value
this.update = (updater) => {
var newValue = updater(data);
this.set(newValue);
};
// Setup event listener
window.wails.Events.On('wails:sync:store:updated:'+name, function(result) {
// Setup event callback
window.wails.Events.On('wails:sync:store:updatedbybackend:'+name, function(result) {
// Parse data
result = JSON.parse(result);
// Todo: Potential preprocessing?
// Save data
data = result;
// Notify listeners
// Notify callbacks
callbacks.forEach( function(callback) {
callback(data);
});

View File

@ -1,5 +1,13 @@
// Package runtime contains all the methods and data structures related to the
// runtime library of Wails. This includes both Go and JS runtimes.
package runtime
import (
"bytes"
"encoding/json"
"reflect"
)
// Options defines the optional data that may be used
// when creating a Store
type Options struct {
@ -16,10 +24,12 @@ type Options struct {
NotifySynchronously bool
}
// StoreProvider is a struct that creates Stores
type StoreProvider struct {
runtime *Runtime
}
// NewStoreProvider creates new stores using the provided Runtime reference.
func NewStoreProvider(runtime *Runtime) *StoreProvider {
return &StoreProvider{
runtime: runtime,
@ -30,21 +40,28 @@ func NewStoreProvider(runtime *Runtime) *StoreProvider {
type Store struct {
name string
data interface{}
dataType reflect.Type
structType bool
eventPrefix string
callbacks []func(interface{})
runtime *Runtime
notifySynchronously bool
// Error handler
errorHandler func(error)
}
// New creates a new store
func (p *StoreProvider) New(name string) *Store {
func (p *StoreProvider) New(name string, defaultValue interface{}) *Store {
result := Store{
name: name,
runtime: p.runtime,
data: defaultValue,
}
result.setupListner()
// initialise the store
result.init()
return &result
}
@ -60,12 +77,90 @@ func (p *StoreProvider) NewWithOptions(options Options) *Store {
return &result
}
func (s *Store) setupListner() {
// Setup listener
s.runtime.Events.On("wails:sync:store:updated:"+s.name, func(data ...interface{}) {
// OnError takes a function that will be called
// whenever an error occurs
func (s *Store) OnError(callback func(error)) {
s.errorHandler = callback
}
// store the data
s.data = data[0]
// init the store
func (s *Store) init() {
// Get the type of the data
s.dataType = reflect.TypeOf(s.data)
// Determine if this is a struct type
s.structType = s.dataType.Kind() == reflect.Ptr
// Setup the sync listener
s.setupListener()
}
// processUpdatedScalar will process the given scalar json
func (s *Store) processUpdatedScalar(data json.RawMessage) error {
// Unmarshall the value
var decodedVal interface{}
err := json.Unmarshal(data, &decodedVal)
if err != nil {
return err
}
// Convert to correct type
if decodedVal == nil {
s.data = reflect.Zero(s.dataType).Interface()
} else {
s.data = reflect.ValueOf(decodedVal).Convert(s.dataType).Interface()
}
return nil
}
// processUpdatedStruct will process the given struct json
func (s *Store) processUpdatedStruct(data json.RawMessage) error {
newData := reflect.New(s.dataType.Elem()).Interface()
err := json.Unmarshal(data, &newData)
if err != nil {
return err
}
s.data = newData
return nil
}
// Processes the updates sent by the front end
func (s *Store) processUpdatedData(data string) error {
var rawdata json.RawMessage
d := json.NewDecoder(bytes.NewBufferString(data))
err := d.Decode(&rawdata)
if err != nil {
return err
}
// If it's a struct process it differently
if s.structType {
return s.processUpdatedStruct(rawdata)
}
return s.processUpdatedScalar(rawdata)
}
// Setup listener for front end changes
func (s *Store) setupListener() {
// Listen for updates from the front end
s.runtime.Events.On("wails:sync:store:updatedbyfrontend:"+s.name, func(data ...interface{}) {
// Process the incoming data
err := s.processUpdatedData(data[0].(string))
if err != nil {
if s.errorHandler != nil {
s.errorHandler(err)
}
}
// Notify listeners
s.notify()
@ -94,10 +189,18 @@ func (s *Store) Set(data interface{}) {
// Save data
s.data = data
// Emit event
s.runtime.Events.Emit("wails:sync:store:updated:"+s.name, s.data)
// Stringify data
newdata, err := json.Marshal(s.data)
if err != nil {
if s.errorHandler != nil {
s.errorHandler(err)
}
}
// Notify listeners
// Emit event to front end
s.runtime.Events.Emit("wails:sync:store:updatedbybackend:"+s.name, string(newdata))
// Notify subscribers
s.notify()
}